【问题标题】:QGraphicsView freeze after scaling缩放后 QGraphicsView 冻结
【发布时间】:2017-07-25 21:00:44
【问题描述】:

我在 Windows 上使用 Qt 4.7

我的qgraphicsview/qgraphicsscene 中有一个错误,在缩放视图后,某些东西会导致“挂起”,这似乎是事件循环中的递归/无限循环。

对于没有简单、完整的代码示例,我深表歉意;我将尽我所能描述症状和情况,我希望有人能提出一两个我可以尝试的想法:

我已将QGraphicsViewQGraphicsSceneQGraphicsItem 子类化。例如,QGraphicsView 中的 wheelEvent 已被子类化以执行以下操作:

scaleView(pow((double)2, -event->delta() / 240.0));

在哪里

void MyGraphicsView::scaleView(qreal scaleFactor)
{
    qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
    if (factor < 0.07 || factor > 100)
        return;

    scale(scaleFactor, scaleFactor);
} 

我的graphicsview子类的构造函数如下:

MyGraphicsView(QWidget *parent) :
  QGraphicsView(parent)
 {
  setRenderHint(QPainter::Antialiasing);
  setTransformationAnchor(AnchorUnderMouse);
  setCacheMode(QGraphicsView::CacheNone);
  setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
  setDragMode(QGraphicsView::ScrollHandDrag);  
 }

我的QGraphicsItem构造函数子类如下:

MyGraphicsItem(QGraphicsObject *parent) :
 QGraphicsObject(parent), 
  _colour(qrand() % 256, qrand() % 256, qrand() % 256),
  _collapsed(false)
{  
  setFlag(ItemIsMovable);
  setFlag(ItemSendsGeometryChanges);
  setCacheMode(DeviceCoordinateCache);
  setZValue(-1);
  expandedPosition(this->pos());
}

我可以将问题隔离为对wheelEvent 的调用,或其他调用QGraphicsView::scaleView 的事件。

如果有一个MyGraphicsItem 可见,那么尝试绘制(或由绘制引起的东西)会导致整个系统挂起。我认为这是事件循环中的一个循环,但要摆脱它(ctrl+alt+del 来调出“开始任务Manager”,然后 esc 取消)我失去了我所在的循环。

循环似乎是对QGraphicsView::focusInEventfocusOutEvent 的重复调用。我已经覆盖了这些,并且无论我对这些函数做什么,似乎都没有太多运气来停止循环。

编辑:这似乎是一条红鲱鱼,是在调试器内切换到断点的结果。

如果视图没有显示MyGraphicsItem,则没有问题。

另外,我可以在缩放后平移和重新绘制视图,但尝试调整窗口大小或更改焦点会导致问题。

同样,如果没有打到scaleView,我也没有问题。

也许我太含糊了;但请回答我能回答的任何问题以帮助澄清。任何帮助表示赞赏! 更新:

所以我似乎把它归结为与我的 QGraphicsItem 子类的子类有关。

我从弹性节点示例中提取了一个节点,并将其放入我的场景中。我可以使用我的 sceven 和 view 放大和缩小,而且不会挂起。

我什至可以让 Node 成为 MyGraphicsItem 的子类,而不是 QGraphicsItem,同样没有手。

只要我将 MyGraphicsItem 的子类放入场景中,我就会发现问题。 我希望越来越近!

【问题讨论】:

  • 尝试升级你的 Qt - 你有一个古老的版本。此类错误通常会在后续版本中修复。
  • 我不能随心所欲地更改 Qt 版本;这是在生产环境中,更改 Qt 版本非常重要:-)
  • 最好尝试找出实际发生的情况(通过 printf() 风格的调试,如果没有别的),但如果所有其他方法都失败了,您可能想尝试将 scaleView() 调用移动到一个单独的上下文,例如通过调用 QTimer::singleShot(0, this, SLOT(myScaleViewSlot())) 而不是直接从处理程序调用 scaleView() 。这样,如果故障是由于调用 scaleView() 的事件循环中的位置引起的,则可以通过从事件循环的不同部分调用它来避免故障。您需要一种方法来传递 scale 参数;也许通过将其存储在成员变量中。
  • 我应该更清楚; scale 函数执行良好并正常返回事件循环。但是在它执行之后,一些事件就会导致问题。例如,我可以平移视图(导致绘制事件)没问题,但我在尝试调整窗口大小或将焦点放在另一个窗口时遇到了问题

标签: c++ qt


【解决方案1】:

进一步更新:

我已经找到了原因。这似乎表明我在某个地方遗漏了一份重要的备忘录。

我有一个测试图形项目,它不是 MyGraphicsItem,但它是 QGraphicsLineItem,这会重现问题。

我已经覆盖了paint方法,经过大量消除后,我发现如果我在paint方法中调用setPen,我的挂起返回。例如,我现在的绘画方法是:

void ConnectionItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
  QWidget *widget)
{ 
  QLineF myline = line();

  QBrush brush(Qt::red); 
  QPen pen = this->pen(); 
  pen.setBrush(brush);
  **// this line results in the hang when the window is resized
  setPen(pen);**

  painter->setPen(pen);
  painter->setBrush(brush);
  painter->drawLine(myline);

}

所以 setPen(将是 QGraphicsLineItem::setPen)调用 update(),然后陷入调用 QGraphicsLineItem::Paint() 的循环中。

故事的寓意:不要在绘制函数中设置笔或其他与绘制相关的属性!

我不是 100% 清楚为什么这只是缩放后的问题,因为绘制例程在缩放之前被非常愉快地调用。

编辑:

类似

QPen pen = this->pen(); 
  pen.setBrush(brush);

导致问题

打电话也是如此

prepareGeometryChange();

在绘画例程中

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    相关资源
    最近更新 更多