在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绘制出来
可以看到此时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,如有高人知道还望指点一二,感激不尽!