【问题标题】:Adding calls inside QgraphicsRectItem subclass triggers infinite redraw在 QgraphicsRectItem 子类中添加调用会触发无限重绘
【发布时间】:2015-06-02 04:14:08
【问题描述】:

我有一个对象类型的层次结构,继承自自定义接口和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()相同
- 一旦没有东西被“固定”在油漆内,油漆就起作用了。

当然,这不起作用——我需要能够设置项目属性,我的理解是调用paint()——在调用更新场景时发生——会更新他的项目。毕竟,我的第一个示例,继承自 QGraphicsItem,有效。

我在question 中发现了类似的东西 - 但没有关于如何修复它的答案,或者没有实际解释为什么调用设置笔和画笔会导致重绘。该代码中没有使用任何项目的绘图属性,甚至更多 - 如果我使用构造函数中的值调用 setPen(m_pen),我看不到需要重新计算...

什么会触发对象重绘以及如何避免它?

【问题讨论】:

    标签: qt inheritance paint


    【解决方案1】:

    QGraphicsRectItem::setPenQGraphicsRectitem::setBrush 都设置项目属性,从而触发更新并重新输入您的 paint。他们必须这样做,毕竟,您要求更改项目!因此,每当您更改形状的钢笔或画笔时,该形状都会自动重新绘制。这是期望的行为。

    如果你想把笔和画笔放在画家身上,就这样做。否则,在您尝试绘制之前设置项目的属性。请记住,钢笔和画笔是独立项的属性,是画家的状态。在谈论它们时,你必须明确你在谈论哪一个。下面的代码说明了这一点。

    也许您只是想将笔/画笔设置在画家身上:

    ...
    painter->setPen(m_pen);
    painter->setBrush(m_brush);
    ...
    

    请记住,paint 的实现绝不能对项目进行任何更改!

    下面是一个例子:

    1. 在绘制QGraphicsRectItem 时如何添加自己的元素。
    2. 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();
    }
    

    【讨论】:

    • @Thalia 我不知道那是什么问题。你想做什么,你不能做什么?当然,如果你在 Item 中有一些代码使它成为一个 mixin 类,你必须对其进行编码,使其发挥应有的作用。例如,它应该在属性更改时安排更新!我认为您的问题是:“我如何实现 QGraphicsItem mixin”,也许......
    • @Thalia 你在问为什么当你从QGraphicsRectItem 继承时代码会崩溃。我告诉你为什么。如果你不是故意要问的,那你为什么还要问这个问题呢?无论如何,如果您有其他问题,请单独提出。请。而且我的意思仍然是 您永远不需要手动强制重新绘制视图/场景!如果你这样做了,你就没有正确地实现你的项目。如果你的Item mixin 没有在必要时安排重绘,那么它就是错误地实现了。
    • @Thalia 当您提出新问题时,请提供完整、可编译的代码,而不是一些片段。从答案中可以看出,功能性、完整和简洁是可能的。此类代码属于您的问题。
    • 我明白你说的。关于请求更新的项目,我把头撞在墙上,我想我找到了解决方案:调用scene-&gt;viewport()-&gt;update() 或其他东西让我不明确调用更新并获得重绘。我会再努力一些。感谢您为我指明正确的方向。
    • @Thalia 是dynamic_cast&lt;QGraphicsItem&gt;(this)-&gt;update() 你在找什么?当您在 C++ 中执行 mixins 时,我几乎可以称其为访问派生类的惯用语。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    相关资源
    最近更新 更多