如何在QML中处理大量的瓷砖?

时间:2016-08-31 08:54:55

标签: qt graphics qml

想象一个巨大的矩形网格,里面装满了瓷砖。单个瓷砖不是很复杂,它们是包含少量形状的svg图像。

不同类型的瓷砖数量不是很大,我估计在数百个。但是,网格可能变得非常大,因此总瓦片数量巨大(至少数万,甚至更多)。

我必须能够水平和垂直地平滑地滚动网格,以及平滑地放大和缩小网格。我也必须能够跳到特定位置。

如果我可以异步填充它,首先是实际可见的元素,然后是其余元素,这也是很好的。这意味着我首先必须在循环中添加行和列的表处理类不是最佳解决方案,因为起始位置不一定是左上角。

通过将图块中项目的所有widthheight属性指定为比例因子的倍数,可以简单地实现缩放。 svg不应该是一个问题,因为不同图像的数量不高,它应该能够被缓存。在svg成为瓶颈的不太可能的情况下,我可以在不同的分辨率中使用不同png的集合。

我尝试(或考虑过)以下方法:

  1. 使用SameGame example的方法,动态创建QML对象(Component.createObject)。如果对象的数量很少,但是对于大量对象来说非常慢,则此方法有效。即使对象完全为空,此方法也需要very long time

  2. Repeater内使用FlickableFlickable包含Grid,其中包含RepaterGrid当然是巨大的。 此方法比动态创建对象更快,但随着切片数量的增长仍然效率低下。 QML引擎跟踪每个项目,甚至是那些不可见的项目。缩放也很慢,因为每个项目的属性都会重新计算,而不仅仅是可见的属性。

  3. 使用GridView。这看起来像乍一看的完美解决方案。 GridView继承Flickable,它也只关注渲染视图范围内的内容。即使是具有数百万svg图像的测试用例运行速度也相当快,并且可以平滑地滚动和调整大小。只有一个问题:GridView只能水平或垂直滑动,但不能同时滑动。自2012年以来一直有feature request,但它似乎仍被忽略。

  4. 直接使用QGraphicsView。它is capable显示,滚动和缩放所需的元素数量,但它不是基于QML的。我的GUI的其余部分是QML,我只阅读有关组合QMLQGraphicsView的恐怖故事。我从未见过任何合理的例子。

  5. 还有哪些其他解决方案?使用Javascript添加和删除简单GridLayout(只有几行和大于可见区域的行)的行和列时,有些可怕的黑客在Flickable中移动了吗?或者只是嵌入一个OpenGL窗口并手动绘制所有内容?

    我希望这不应该是一项不可能完成的任务。 20多年前为DOS和Windows 95编写的策略游戏可以处理这些数量的磁贴,同时还具有纹理和动画。

1 个答案:

答案 0 :(得分:1)

是的,Qt非常善于忽视多年来的社区建议,即使它们非常有用,被认为是重要的,并且碰巧是最高投票的,例如zip support

我个人不会打扰"修复" GridView,而是在C ++中实现适合我的特定要求的一些东西,以便快速有效。如果你的瓷砖是均匀的方块,那就很容易了,听起来就像你可以逃脱它,即使里面的实际图像不是正方形。这将使得以编程方式确定其位置非常容易,并且还确定左上角的区块,每行多少区块以及后续线的步幅。然后,当可见性矩形移动时,您将迭代容器并发出信号,为那些进入可见性的人创建QML元素。容易腻。

你不需要任何花哨的东西,只需继承QObject,将类型注册到QML,然后去填充它的内部"模型"。你绝对不希望所有的对象都在内存中,即使场景图很聪明而不能渲染它们,它仍然会处理它们,我怀疑你的FPS不是GPU的产物而是CPU瓶颈。

实际网格对象可以使用其数据Q_SIGNAL void create(x, y, imgPath);发出创建和销毁信号,因此您可以在QML端绑定自定义处理程序,这将为您提供灵活性和易用性,例如轻松指定&#34 ;委托"对象,它比在C ++中实际创建/销毁更优雅。你可以在QML一侧使用绑定来查看当他们离开屏幕进行自毁时可以跟踪的几个项目,这样可以最大限度地减少复杂性,因为你不必跟踪所有"生活& #34;对象。

Component {
   id: objComponent
   Image {
      property bool isVisible: { is in grid.visibleRect ??? }
      onIsVisibleChanged: if (!isVisible) destroy()
   }
}

MyGrid {
  id: grid
  contentX: flickable.contentX
  contentY: flickable.contentY

  onCreate: objComponent.createObject(flickable.contentItem, {"x" : x, "y" : y, "source" : imgPath})
}

Flickable {
   id: flickable
   contentWidth: grid.contentWidth
   contentHeight: grid.contentHeight
}

通常情况下,当用户提出问题时,重要的是提供奖金我会生成工作代码,但不幸的是我现在太忙了。这个概念非常简单,不应该太难实现。