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

在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 Description
Qt::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绘制出来
关于子类化QGraphicsTextItem只有很小一部分区域能够获取事件的问题_第1张图片
可以看到此时boundingRect完完全全的把QString包含起来,按照一般Item,点击boundingRect区域,应该会有鼠标事件,焦点事件发生,但事实却不尽然。
经过尝试,发现似乎即使重写QGraphicsTextItem的boundingRect函数,TextItem却视而不见,依然使用自身的一套系统来计算其有效区域,所以子类化QGraphicsTextItem并自行使用Painter绘制字体的时候,不仅要对painter setFont,还要对QGraphicsTextItem本身设置font与plainText,这样QGraphcisTextItem才能正确计算出自身的事件有效区域;

下面贴上代码:
frametext.h

#ifndef FRAMETEXT_H
#define FRAMETEXT_H

#include 
#include 
#include 

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 
#include 
#include 

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,如有高人知道还望指点一二,感激不尽!

你可能感兴趣的:(qt学习)