2017-07-24 61 views
0

我在WindowsQt 4.7QGraphicsView缩放后冻结

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

我很抱歉没有一个简单的,完整的代码示例;我将描述的症状,情况,尽我所能,而且我希望有人将有一个或两个想法,我可以尝试:

我有子类QGraphicsViewQGraphicsSceneQGraphicsItem。例如,wheelEventQGraphicsView已经子类执行以下操作:

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 + 德尔,弹出“启动任务管理器”,然后ESC取消)我失去了环路我在

该循环似乎是重复呼叫QGraphicsView::focusInEventfocusOutEvent。我已经重写了这些,并且在停止循环方面似乎没有太多的运气,不管我使用这些函数做什么。

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

如果视图未显示MyGraphicsItem,则不存在问题。

还有,我可以在缩放后重新绘制视图,但试图调整窗口大小或改变焦点会导致问题。

同样,如果还没有打电话给scaleView,我没有问题。

也许我太模糊了;但请解答任何我可以帮助澄清的问题。任何帮助感谢! 更新:

所以我似乎已经把它归结为我的子类的QGraphicsItem的一个子类。

我从弹性节点的例子中得到一个节点,并把它放在我的场景中。我可以放大和缩小使用我的场景和视图,并且不会挂起。

我甚至可以让Node成为MyGraphicsItem的一个子类而不是QGraphicsItem,并且再次没有任何问题。

只要我将MyGraphicsItem的子类放入场景中,我就会看到问题。 靠近我希望!

+0

尝试升级你的Qt - 你有一个古老的版本。这些错误通常在后续版本中修复。 –

+0

我不能随便改变Qt版本;这是在一个生产环境中,改变Qt版本是相当重要的:-) – mike

+0

最好尝试找出实际发生了什么(如果没有别的东西,通过printf()样式调试),但如果其他您可能想尝试将您的scaleView()调用移至单独的上下文,例如失败通过调用QTimer :: singleShot(0,this,SLOT(myScaleViewSlot())),而不是直接从处理程序调用scaleView()。这样,如果故障是由调用scaleView()的event-loop中的位置引起的,则可以通过调用它而不是事件循环的不同部分来避免该故障。您需要一种方法来传递比例参数;也许通过将其存储在一个成员变量中。 –

回答

0

进一步更新:

我发现这样做的原因。这似乎表明我错过了某处的重要备忘录。

我有一个不是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()方法。

道德故事:不要在绘画功能中设置Pen或其他与绘画相关的属性!

我不是100%清楚为什么这只是缩放后的问题,因为在缩放之前调用paint例程相当愉快。

编辑:

同样

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

导致问题

如不调用

prepareGeometryChange(); 

油漆例程中