2013-10-02 22 views
1

我試圖做一個規則像這樣的時間表:Qt:QGraphicsScene :: addText中的內存泄漏?

Timeline

我有一個的QGraphicsView這裏我把一個QGraphicsScene,我添加像線條和一些標籤QGraphicsItems。

只有在縮放變化時(而不是在paintEvent引發時),纔會將元素添加到場景中。

,其將時刻標籤,我用:

QString label = "00:14"; // For example 
    int posX = ... // Here I calculate the position of the label 
    scene->addText(label,QFont("Arial",8))->setPos(posX,-1); 

當我不得不重新繪製的規則,我做:

qDeleteAll(scene->items()); 

在beggining,然後重新添加標籤和線條。

我意識到我的表現不好。我的場景有8k元素(線條和標籤之間),所以我使用Valgrind來檢查問題。

它顯示'可能'我有內存泄漏在我添加文本到場景的行中。我有一些看起來像這樣的消息:

2,165,760 bytes in 470 blocks are possibly lost in loss record 9,922 of 9,923 
     in TimelineWidget::drawRule() in Timeline/timelinewidget.cpp:166 
     1: realloc in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 
     2: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     3: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     4: QTextDocument::setPlainText(QString const&) in /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     5: /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     6: QGraphicsTextItem::QGraphicsTextItem(QString const&, QGraphicsItem*, QGraphicsScene*) in /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     7: QGraphicsScene::addText(QString const&, QFont const&) in /usr/lib/x86_64-linux-gnu/libQtGui.so.4.8.3 
     8: TimelineWidget::drawRule() 

這隻發生在addText調用,而不是addLine調用。

我使用Qt的4.8和我的問題是:

  • 那些是內存泄漏是真的嗎?

  • 我做錯了什麼?

  • 是否有另一種/更好的方法來實現我的規則?

在此先感謝!

+0

你怎麼能有8K元素?! –

+0

我每隔一行加上一段時間的標籤。例如: 0 0:10 0:20 | .... | .... | .... | .... | .... 等一個2小時! (60s * 60m * 2h = 7200行) –

+0

如果您顯示包含視頻整個持續時間的完全縮小時間線,則沒有人能看到如此多的線條和標籤。您必須顯示合理數量的刻度線,並根據縮放級別調整刻度週期。 –

回答

2

我建議以下所有條件:

  1. 相反的qDeleteAll(scene->items()),簡單地清場:

    scene->clear(); 
    
  2. 使用scene->addSimpleText如果你沒有顯示豐富的文本。

  3. 對於簡單的重複項目,例如一組具有固定間距的線條,可創建可重複使用的自定義項目。這些將比爲每條線創建圖形場景項目更快並且開銷更低。內存,索引,樹遍歷和查找開銷將從O(N)下降到O(1)的線條數量方面

    假設您已經創建了一個自定義項目,它是一個水平行數組:| | | | | | | | |。該項目只是繪製固定數量的線條。您可以調整項目大小以更改線條的高度以及線條的橫向區域。請記住在您的paint()方法中重置筆,因爲默認筆將被重新縮放,因此可能非常寬。

    一個簡單的未標記標尺可以通過疊加三個項目獲得:兩個線陣和一條水平線。

您可能還想重新架構如何處理場景。到目前爲止,您將場景當作整個時間線的模型。相反,您應該至少將其中的一部分視爲視圖模型。

您的時間軸有兩個主要元素:規則和剪輯預覽。

當您在給定縮放級別滾動規則時,您會注意到總是有相同數量的線條和標籤可見。唯一改變的是線條的輕微水平偏移,當然標籤的值也會改變。

所以,不要將場景中的所有線條和所有標籤都包含在當前視圖中,而只需在當前視圖中調整其大小,調整其在場景中的水平位置,以使它們在正確的偏移量處可見;以及修正標籤文字。這就是它的一個view model - 這是一個與特定視圖緊密相連的模型。底層抽象模型是一個非常長的統治者,但我們只需要它是一個抽象模型,而不是一個佔用內存和其他資源的模型。

剪輯預覽可以在您滾動時動態添加並從場景中移除。這可以爲你節省大量的內存,因爲我認爲你有很多圖像,其中大部分是不可見的。

您顯示的示例屏幕截圖有一些用戶設計問題:顯示水平截斷的重疊剪輯預覽顯得毫無意義。在任何給定的縮放級別下,您都應該有一個您願意顯示的最小預覽大小。顯示那些狹窄的垂直像素條非常昂貴。以下是可能的算法來處理它。

假設預覽項目是從左到右排列的矩形。

  1. 從與視口矩形相交的最左邊的項目(場景座標中的所有東西)開始。使其成爲current_item

  2. 顯示current_item(將其添加到場景中)。

  3. 繼續採取下一個項目,而他們重疊current_item。存儲last_overlapping_item(如果沒有項目重疊,它可以爲空)。

  4. 將當前項目保存在previous_item中。採取下一個項目,並使其current_item

  5. 如果有current_itemprevious_item之間沒有縫隙,清除last_overlapping_item,因爲它是完全由相鄰的當前和以前的項目重疊。

  6. 顯示last_overlapping_item如果有(將其添加到場景中)。

  7. 如果current_item完全位於視口矩形之外,則表示完成。否則,請轉到2。

+0

感謝您的建議庫巴!另外,我使用了scene-> setItemIndexMethod(NoIndex)並減少了場景項的數量,並且加快了執行速度!你能解釋更多第三點嗎?另一方面,你對於mem漏洞有什麼看法? –

+0

我演示的圖像來自Adobe Premiere,我只想顯示規則的外觀。再次感謝庫巴! –