在 QgraphicsRectItem 子类中添加调用会触发无限重绘
Adding calls inside QgraphicsRectItem subclass triggers infinite redraw
我有一个对象类型层次结构,继承自自定义接口和 QGraphicsItem
。
希望优化代码,想继承QGraphicsSomethingItem
。示例:矩形
class RectangleItem : public Item, public QGraphicsItem
{
RectangleItem() : Item() // Item initializes m_pen, m_brush
{
setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable |
QGraphicsItem::ItemIsSelectable);
}
QRectF RectangleItem::boundingRect() const
{
return QRectF(-50, -50, 100, 100);
}
void RectangleItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
setItemPen(); // calculates m_pen in class Item
setItemBrush(); // calculates m_brush in class Item
painter->setPen(m_pen);
painter->setBrush(m_brush);
painter->drawRect(boundingRect());
}
}
这非常有效。
现在尝试同样的事情但是继承自 QGraphicsRectItem
class RectangleItem : public Item, public QGraphicsRectItem
{
RectangleItem() : Item() // Item initializes m_pen, m_brush
{
setRect(-50, -50, 100, 100);
setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable |
QGraphicsItem::ItemIsSelectable);
}
QRectF RectangleItem::boundingRect() const
{
return QRectF(-50, -50, 100, 100);
}
void RectangleItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
// setItemPen(); // calculates m_pen in class Item
// setItemBrush(); // calculates m_brush in class Item
setPen(m_pen);
setBrush(m_brush);
QGraphicsRectItem::paint(painter, option, widget);
}
}
这将创建一个无限循环
- setItemPen()
上的断点显示它一直在调用它。所以我删除了它,连同 setItemBrush()
。 (虽然我真的需要设置自定义笔)
- setPen()
上的断点显示它一直在调用它。所以我删除了它。与 setBrush()
相同
- 一旦油漆内没有任何东西"set",油漆就起作用了。
当然这不是功能性的 - 我需要能够设置项目属性,我的理解是调用 paint()
- 在调用更新场景时发生 - 会更新他的项目。毕竟,我的第一个示例(继承自 QGraphicsItem
)有效。
我在这个 question 中发现了类似的东西 - 但没有关于如何修复它的答案,也没有实际解释为什么调用设置笔和画笔会导致重绘。该代码中没有使用项目的任何绘图属性的任何内容,甚至更多 - 如果我使用构造函数的值调用 setPen(m_pen)
,我看不到任何需要重新计算的内容...
什么会触发对象重绘,我该如何避免?
QGraphicsRectItem::setPen
和 QGraphicsRectitem::setBrush
都设置了项目属性,从而触发更新并重新输入您的 paint
。他们 必须 这样做,毕竟,您要求更改项目!所以,任何时候你改变形状的笔或画笔,形状都会自动重新绘制。这是理想的行为。
如果你想在画家身上设置笔和画笔,就这样做吧。否则,在您尝试绘画之前设置项目的属性。请记住,笔和画笔是画家状态的 和 项的 独立 属性。谈论它们时,您必须明确您谈论的是哪一个。下面的代码说明了这一点。
也许您只是想在 painter 上设置 pen/brush:
...
painter->setPen(m_pen);
painter->setBrush(m_brush);
...
记住,paint 的实现绝不能对项目进行任何更改!
这里有一个例子显示:
- 如何在绘制
QGraphicsRectItem
时添加自己的元素。
setPen
会触发自动重绘。
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QTimer>
class XRectItem : public QGraphicsRectItem {
void paint(QPainter *p, const QStyleOptionGraphicsItem *opt, QWidget *wdg = 0)
Q_DECL_OVERRIDE
{
QGraphicsRectItem::paint(p, opt, wdg);
// optional
if (false)
p->setPen(QPen(QColor(rand() % 256, rand() % 256, rand() % 256), 0.1));
p->drawEllipse(rect());
}
public:
XRectItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem * parent = 0) :
QGraphicsRectItem(x, y, w, h, parent) {}
};
class View : public QGraphicsView
{
void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE {
fitInView(sceneRect(), Qt::KeepAspectRatio);
}
public:
View(QGraphicsScene *scene, QWidget *parent = 0) :
QGraphicsView(scene, parent) {}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene s;
XRectItem rect(-1.5, 1.5, 3, 2);
s.addItem(&rect);
QTimer timer;
timer.start(100);
QObject::connect(&timer, &QTimer::timeout, [&rect]{
rect.setPen(QPen(QColor(rand() % 256, rand() % 256, rand() % 256), 0.1));
});
View v(&s);
v.setRenderHint(QPainter::Antialiasing);
v.show();
return a.exec();
}
我有一个对象类型层次结构,继承自自定义接口和 QGraphicsItem
。
希望优化代码,想继承QGraphicsSomethingItem
。示例:矩形
class RectangleItem : public Item, public QGraphicsItem
{
RectangleItem() : Item() // Item initializes m_pen, m_brush
{
setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable |
QGraphicsItem::ItemIsSelectable);
}
QRectF RectangleItem::boundingRect() const
{
return QRectF(-50, -50, 100, 100);
}
void RectangleItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
setItemPen(); // calculates m_pen in class Item
setItemBrush(); // calculates m_brush in class Item
painter->setPen(m_pen);
painter->setBrush(m_brush);
painter->drawRect(boundingRect());
}
}
这非常有效。
现在尝试同样的事情但是继承自 QGraphicsRectItem
class RectangleItem : public Item, public QGraphicsRectItem
{
RectangleItem() : Item() // Item initializes m_pen, m_brush
{
setRect(-50, -50, 100, 100);
setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable |
QGraphicsItem::ItemIsSelectable);
}
QRectF RectangleItem::boundingRect() const
{
return QRectF(-50, -50, 100, 100);
}
void RectangleItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
// setItemPen(); // calculates m_pen in class Item
// setItemBrush(); // calculates m_brush in class Item
setPen(m_pen);
setBrush(m_brush);
QGraphicsRectItem::paint(painter, option, widget);
}
}
这将创建一个无限循环
- setItemPen()
上的断点显示它一直在调用它。所以我删除了它,连同 setItemBrush()
。 (虽然我真的需要设置自定义笔)
- setPen()
上的断点显示它一直在调用它。所以我删除了它。与 setBrush()
相同
- 一旦油漆内没有任何东西"set",油漆就起作用了。
当然这不是功能性的 - 我需要能够设置项目属性,我的理解是调用 paint()
- 在调用更新场景时发生 - 会更新他的项目。毕竟,我的第一个示例(继承自 QGraphicsItem
)有效。
我在这个 question 中发现了类似的东西 - 但没有关于如何修复它的答案,也没有实际解释为什么调用设置笔和画笔会导致重绘。该代码中没有使用项目的任何绘图属性的任何内容,甚至更多 - 如果我使用构造函数的值调用 setPen(m_pen)
,我看不到任何需要重新计算的内容...
什么会触发对象重绘,我该如何避免?
QGraphicsRectItem::setPen
和 QGraphicsRectitem::setBrush
都设置了项目属性,从而触发更新并重新输入您的 paint
。他们 必须 这样做,毕竟,您要求更改项目!所以,任何时候你改变形状的笔或画笔,形状都会自动重新绘制。这是理想的行为。
如果你想在画家身上设置笔和画笔,就这样做吧。否则,在您尝试绘画之前设置项目的属性。请记住,笔和画笔是画家状态的 和 项的 独立 属性。谈论它们时,您必须明确您谈论的是哪一个。下面的代码说明了这一点。
也许您只是想在 painter 上设置 pen/brush:
...
painter->setPen(m_pen);
painter->setBrush(m_brush);
...
记住,paint 的实现绝不能对项目进行任何更改!
这里有一个例子显示:
- 如何在绘制
QGraphicsRectItem
时添加自己的元素。 setPen
会触发自动重绘。
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QTimer>
class XRectItem : public QGraphicsRectItem {
void paint(QPainter *p, const QStyleOptionGraphicsItem *opt, QWidget *wdg = 0)
Q_DECL_OVERRIDE
{
QGraphicsRectItem::paint(p, opt, wdg);
// optional
if (false)
p->setPen(QPen(QColor(rand() % 256, rand() % 256, rand() % 256), 0.1));
p->drawEllipse(rect());
}
public:
XRectItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem * parent = 0) :
QGraphicsRectItem(x, y, w, h, parent) {}
};
class View : public QGraphicsView
{
void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE {
fitInView(sceneRect(), Qt::KeepAspectRatio);
}
public:
View(QGraphicsScene *scene, QWidget *parent = 0) :
QGraphicsView(scene, parent) {}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene s;
XRectItem rect(-1.5, 1.5, 3, 2);
s.addItem(&rect);
QTimer timer;
timer.start(100);
QObject::connect(&timer, &QTimer::timeout, [&rect]{
rect.setPen(QPen(QColor(rand() % 256, rand() % 256, rand() % 256), 0.1));
});
View v(&s);
v.setRenderHint(QPainter::Antialiasing);
v.show();
return a.exec();
}