2017-07-24 129 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(); 

油漆例程中