Qt:QGraphicsScene :: addText中的内存泄漏?

时间:2013-10-02 15:48:08

标签: c++ qt memory-leaks

我正在尝试为这样的时间轴制定规则:

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());

在开始,然后再次添加标签和行。

我意识到我的表现不好。我的场景有类似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 ,我的问题是:

  • 这些内存泄漏是否真实?

  • 我做错了吗?

  • 是否有其他/更好的方式来实施我的规则?

提前致谢!

1 个答案:

答案 0 :(得分:2)

我建议以下所有内容:

  1. 而不是qDeleteAll(scene->items()),只需清除场景:

    scene->clear();
    
  2. 如果您没有显示富文本,请使用scene->addSimpleText

  3. 对于简单重复的项目(例如一组固定间距的行),创建可重复使用的自定义项目。与为每条线创建图形场景项相比,这些将更快并且开销更低。根据绘制的行数,内存,索引,树遍历和查找开销将从O(N)下降到O(1)

    假设您已经创建了一个自定义项,它是一个水平线阵列:| | | | | | | | |。该项目仅绘制固定数量的线条。您可以调整项目的大小以更改线条的高度和它们所跨越的水平区域。请记住在paint()方法中重置笔,因为默认笔会重新缩放,因此可能非常宽。

    可以通过叠加三个项目来获得具有主要和次要刻度的简单未标记标尺:两个线阵列和一个水平线。

  4. 您可能还想重新构建对待场景的方式。到目前为止,您将场景视为整个时间轴的模型。相反,您应该至少将其中的一部分视为视图模型。

    时间轴有两个主要元素:规则和剪辑预览。

    当您以给定的缩放级别滚动规则时,您会注意到总是有相同数量的线条和标签可见。唯一改变的是线的轻微水平偏移,当然标签的值也会改变。

    因此,不是在场景中拥有所有线条和所有标签,而是只有适合当前视图的数量,调整它们在场景中的水平位置,以便它们在正确的偏移处可见,并修复标签文字。这就是它成为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.