Imagine a huge rectangular grid filled with tiles. The individual tiles are not very complicated, they are svg images containing a low amount of shapes.
The number of different types of tiles in not very large, I estimate in the low hundreds. However, the grid can become very large, so the number of total tiles is huge (at least tens of thousands, maybe more).
I have to be able to smoothly scroll the grid both horizontally and vertically, as well as smoothly zoom it in and out. I also have to be able to jump to a specific position.
It would also be nice if I could populate it asynchronously, first the elements which are actually visible, and then the rest. This means that a table-handling class where I first have to add rows and columns in a loop would not be the best solution, because the starting position is not necessarily the upper left corner.
Zooming is simply achieved by having all the width
and height
properties of the items within a tile specified as a multiple of a scaling factor. The svg
shouldn't be a problem as the number of different images is not high, it should be able to be cached. In the unlikely case svg
became the bottleneck, I could just use sets of different png
s in different resolutions.
I tried (or considered) the following approaches:
Using the methods of the SameGame example, creating QML objects dynamically (
Component.createObject
). This works if the number of objects is small, but is very slow with a large number of objects. Even if the objects are completely empty, this method takes a very long time.Using a
Repeater
inside aFlickable
. TheFlickable
contains aGrid
, which is populated by aRepater
. TheGrid
, of course, is immense. This method is faster than creating the objects dynamically, but still inefficient as the number of tiles grows. The QML engine keeps track of every item, even those which are not visible. Zooming is also quite slow, as the properties of every item are recalculated, not just the visible ones.Using a
GridView
. This looks like the perfect solution at a first glance. TheGridView
inheritsFlickable
, and it also takes care to only render contents which are within the bounds of the view. Even a test case with millions of svg images runs reasonably fast, and it scrolls and resizes smoothly. There is only one problem: TheGridView
is only flickable either horizontally or vertically, but not both. There has been a feature request about this since 2012, but it still seems to be ignored.Using a
QGraphicsView
directly. It is capable of displaying, scrolling and zooming the needed amount of elements, but it's not QML-based. The rest of my GUI is in QML, and I've only read horror stories about combiningQML
andQGraphicsView
. I've never seen any reasonable examples of it.
What other solutions are there? Some horrible hack of using Javascript to add and remove rows and columns of a simple GridLayout
(which is only a couple rows and columns larger than the visible area) while it is moved around in a Flickable
? Or just embedding an OpenGL window and drawing everything manually?
I hope this shouldn't be an impossible task. There were strategy games written more than 20 years ago for DOS and Windows 95 which could handle this amount of tiles, while additionally having textures and animations.