关于子类化QGraphicsTextItem只有很小一部分区域能够获取事件的问题

来源:互联网 发布:超级玛丽 跳跃算法 编辑:程序博客网 时间:2024/05/23 14:57

在QT图形视图框架中,想要Item响应获得焦点事件,首先需要设置本Item可以获得焦点
一般Item可以使用

setFlag(QGraphicsItem::ItemIsFocusable);

来使Item可以获取焦点事件,但是针对QGraphicsTextItem,它有一个另外的设置方法,首先来看这个方法的函数原型

void setTextInteractionFlags(Qt::TextInteractionFlags flags)

帮助文档中对这个方法是这样解释的:
Sets the flags flags to specify how the text item should react to user input.

The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function also affects the ItemIsFocusable QGraphicsItem flag by setting it if flags is different from Qt::NoTextInteraction and clearing it otherwise.

By default, the text is read-only. To transform the item into an editor, set the Qt::TextEditable flag.

这样就比较清晰了,参数flags代表了QGraphicsTextItem的一些属性,
再来看看Qt::TextInteractionFlags

This enum specifies how a text displaying widget reacts to user input.Constant Value DescriptionQt::NoTextInteraction           0   No interaction with the text is possible.Qt::TextSelectableByMouse       1   Text can be selected with the mouse and copied to the clipboard using a context menu or standard keyboard shortcuts.Qt::TextSelectableByKeyboard    2   Text can be selected with the cursor keys on the keyboard. A text cursor is shown.Qt::LinksAccessibleByMouse      4   Links can be highlighted and activated with the mouse.Qt::LinksAccessibleByKeyboard   8   Links can be focused using tab and activated with enter.Qt::TextEditable                16  The text is fully editable.Qt::TextEditorInteraction   TextSelectableByMouse | TextSelectableByKeyboard | TextEditable The default for a text editor.Qt::TextBrowserInteraction  TextSelectableByMouse | LinksAccessibleByMouse | LinksAccessibleByKeyboard  The default for QTextBrowser.

它是一个枚举,每个枚举代表不同的QGraphicsTextItem属性,比如Qt::NoTextInteraction,设置这个属性的话QGraphicsTextItem就只是个能显示字符串的Item,没有输入,选中功能;而Qt::TextEditable表示启用QGraphicsTextItem的所有功能;QGraphicsTextItem默认属性为Qt::TextBrowserInteraction,这个属性是一个聚合属性,其中一个是TextSelectableByMouse,表明可以被鼠标选中,既然可以被选中,就表明可以获取焦点,我们可以使用

setTextInteractionFlags(Qt::TextBrowserInteraction);

来使得QGraphicsTextItem可以获取焦点。
当然

setFlag(QGraphicsItem::ItemIsFocusable);

对QGraphicsTextItem同样是有效的。

好了现在开始说正题:

问题:
子类化QGraphicsTextItem并setTextInteractionFlags(Qt::TextBrowserInteraction);,在paint事件中使用painter自行绘制想要显示的字符串

painter->drawText(boundingRect(),Qt::AlignCenter,m_text);

即使重写了boundingRect()虚函数,并返回了正确的区域,但是QGraphicsTextItem却只有很小一部分区域能够获取到事件

分析与解答:
在正确setFlag的情况下,依然无法获取到焦点事件,那么多半是boundingRect()的问题,我们有必要在paint事件中将boundingRect画出来,不过问题中说了,已经在重写的boundingRect虚函数返回了正确的QRectF区域,如下图所示,我们将boundingRect绘制出来
这里写图片描述
可以看到此时boundingRect完完全全的把QString包含起来,按照一般Item,点击boundingRect区域,应该会有鼠标事件,焦点事件发生,但事实却不尽然。
经过尝试,发现似乎即使重写QGraphicsTextItem的boundingRect函数,TextItem却视而不见,依然使用自身的一套系统来计算其有效区域,所以子类化QGraphicsTextItem并自行使用Painter绘制字体的时候,不仅要对painter setFont,还要对QGraphicsTextItem本身设置font与plainText,这样QGraphcisTextItem才能正确计算出自身的事件有效区域;

下面贴上代码:
frametext.h

#ifndef FRAMETEXT_H#define FRAMETEXT_H#include <QGraphicsTextItem>#include <QFontMetricsF>#include <QPen>class FrameText : public QGraphicsTextItem{public:    FrameText();    ~FrameText();    QRectF boundingRect();    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);    void setText(QString);    void setFontSize(int);private:    QString m_text;    QPen m_pen;    QFont m_font;    int m_fontSize;    bool m_focus;    QFontMetricsF *m_fontMetricsF;    qreal m_fontWidth;    qreal m_fontHeight;    void updateFontInfo();    void focusInEvent(QFocusEvent *);    void focusOutEvent(QFocusEvent *);};#endif // FRAMETEXT_H

frametext.cpp

#include "frametext.h"#include <QPainter>#include <QDebug>#include <QStyleOptionGraphicsItem>FrameText::FrameText(){    setTextInteractionFlags(Qt::TextEditorInteraction);    m_fontMetricsF=Q_NULLPTR;    m_text="";    m_font.setFamily("msyhl");    m_font.setPixelSize(20);    m_focus=false;}FrameText::~FrameText(){    delete m_fontMetricsF;}QRectF FrameText::boundingRect(){//  qDebug()<<"boundingRect";    return QRectF(0,0,m_fontWidth,m_fontHeight);}void FrameText::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){//  qDebug()<<"paint";    painter->save();    if(m_focus==true)        m_pen.setColor(Qt::blue);    else        m_pen.setColor(Qt::black);    painter->setPen(m_pen);    painter->setFont(m_font);    painter->setRenderHint(QPainter::Antialiasing,true);    painter->drawText(boundingRect(),Qt::AlignCenter,m_text);    painter->drawRect(boundingRect());    painter->restore();}void FrameText::setText(QString text){    m_text=text;    updateFontInfo();}void FrameText::setFontSize(int size){    m_fontSize=size;    m_font.setPixelSize(m_fontSize);    updateFontInfo();}void FrameText::updateFontInfo()        //计算m_fontWidth,m_fontHeight给自定义的boundingRect使用,同时为QGraphicsTextItem设置font和plainText{    if(Q_NULLPTR!=m_fontMetricsF)        delete m_fontMetricsF;    m_fontMetricsF=new QFontMetricsF(m_font);    m_fontWidth=m_fontMetricsF->width(m_text);    m_fontHeight=m_fontMetricsF->height();    this->setFont(m_font);    this->setPlainText(m_text);}void FrameText::focusInEvent(QFocusEvent *focusEvent)        //获得焦点事件{    //qDebug()<<"focus in";    Q_UNUSED(focusEvent);    m_focus=true;    this->update();}void FrameText::focusOutEvent(QFocusEvent *focusEvent)      //失去焦点事件{    Q_UNUSED(focusEvent);    //qDebug()<<"focus out";    m_focus=false;    this->update();}

为什么QGraphcisTextItem不使用重写的boungingRect虚函数,本人也是初学QT,如有高人知道还望指点一二,感激不尽!

原创粉丝点击