Grid vs GridLayout vs GridView



  • Hello all,

    I am on my way to implementing a re sizable Grid that houses Items experiencing real time updates.

    Before I choose my Type, I am curious to hear from others: Grid vs. GridLayout vs. GridView?

    I have used ListView before, so I understand model-view-delegate architecture.

    My question is, what do each of these offer, and what are some common setups?

    My initial thinking would be to use a GridView, within a GridLayout. Is this correct/feasible?

    Thanks!

    Edit: If you are just going to post a link to Qt Documentation, you're just wasting both of our time, as that is what I'm reviewing right now. My reason for posting this is to hear what other developers have done and what their experience was like.



  • First question you probably have to ask yourself is how you get the Elements, which should be displayed.

    Grid and GridLayout do position your Elements. So you have already existing Elements, like 4 Rectangles and want them in a grid. It's really easy to say how exactly they should be displayed ... 4 Row, 4 Columns, 2 Rows and 2 Columns ... spacing ...

    From my point of view, I consider them for a static number of Elements. Because you either declare all Elements in a qml or in case you have always have the same Element (more or less) you use it together with a Repeater. At least in the first case it's no problem to make changes on the Elements as you can give them all id's. With a Repeater this is probably not that easy.

    If you decide to use this approach, you still need to know if you should use Grid or GridLayout:

    In General, you should use Grid if you want the Grid to be static. In a Grid you define the width and the height of each Element and therefore the Elements will only take the space they need.
    In a GridLayout the Elements usually take as much space as they have. At least if you define your Elements to fillWidth or fillHeight. Of course you can give them also a fixed width or height, but there must be at least one Item, which cover the rest.
    For Example:

    One dimensional(width, height)
    Element1(20,20) Element2(20,20) Item(fillWidth, 20) Element3(20,20)

    If you now resize the whole Application, the Item will get resized, whereas the Elements will always have 20,20. If you make all your Elements fillWidth, fillHeight, then every elements gets smaller or bigger if you resize your application.

    Use Grid if it has to be static and GridLayout for resizable things.

    Or your third option: GridView

    GridView is the best approach if you have a model, for example if you want to do a file Manager. You really don't know how many folders there will be the directory you are.
    As you have a model, you can also easily to changes in it.

    Unconfigured it's in point of resizable better than Grid, as your Elements don't go off the screen. But instead the GridView will become a Flickable, which you can scroll.
    As the Grid View it takes as much space as needed, even if there is more space.

    But with some configuration you can make it behave like a GridLayout ... for example you can bind the cellWidth and cellHeight to the applications height and width.
    Of course this is a little bit more tricky as you may need to do some calculations (how many Elements in one row, in one column, available space, length of the model ....) to get the reigth cellWidth and cellHeight. Furthermore, you also have to calculate spacing by yourself (by making cellWidth/cellHeight bigger than the actual Element).

    In conclusion, you have the choice between GridLayout and GridView depending on how you get your Elements (from a model, already defined in qml ...). If you want it to be resizable it's of course much easier to use GridLayout, but if have understand you correctly, you probably need a model and therefore have to go with GridView. (Which is perfectly fine, just a little bit more work to configure).

    A GridView within a GridLayout would be a Grid with lots of Grids. I don't think this is what you need?



  • @Leon_2001 Thanks for the reply! I ended up taking the approach of making a ListView of ListViews.

    • The first step I took was creating Cell.qml : just a basic Rectangle with a string inside.

    • Second step was creating CustomRow.qml: Just 3 Cells in a RowLayout.

    • Third step was creating CustomGrid.qml, which is basically a Rectangle with a ListView inside. The model for this ListView came from my context property, and I used CustomRow as my delegate.

    • Finally, fourth step was to create a ListView in my Display.qml (the one inside main.qml), where I used context property again for the model, and the delegate was CustomGrid.

    Although this seems complicated, It's really just a bunch of components broken down, with the desired functionalities addressed.

    Although, while we are here, I do have a question regarding the ListView model property.

    Let's say we have registered Model.cpp as a context property of the QML engine. Let's also say that Model.cpp contains a few QVectors that contain important data-related information, including how many items should be visualized.

    Logically, for our ListView, we could assign the model property to be something like:
    model: ModelContextProperty.getLengthofDataVector()

    So my question is, when the length of this data vector is modified (say, we add or remove a data item), how does QML react?

    Knowing that the delegate property is Component based, does it recognize that the model has been modified, start at index==0, and reload each delegate Component? My plan is to make another post regarding this topic, but I figured I may as well ask the question here too.



  • First of all I am glad that you found a solution you're happy with.
    Nevertheless, I still recommend to use GridView. On the one hand, it probably reduces your amount of code, on the other hand, and most importantly, it's much more readable to you and every other developer, who might want to help you or needs some Inspiration, because he has the same problems as you have.

    To your question:

    On of the key features of Qml is property binding. So let's say you have

    import QtQuick.Controls 2.3 
    
    ApplicationWindow {
      id: root
      width: 600; height: 600
      visible: true 
    
      Rectangle {
         width: parent.width/2; height: parent.height/2
         color: "blue"
      }
    
      MouseArea {
         anchors.fill: parent 
         onClicked:  { root.width -= 10; root.height += 10; }
      }
    }
    

    If you click the applicationWindow its width will be decreased by 10 and its height increased by 10. At the same time the rectangle's width will be decreased by 5 and its height increased by 5. That's because its size depends on the size of the applicationWindow and will be changed automatically.

    Same applies to your case. If the model changes its size, your ListView should notice this and update the list.

    Just in case you don't know (or if it's working in your case, didn't know how your model looks like) you can do:
    model: yourModelName.length
    or if it's a List of Arrays/Vectors
    model: yourModelName[index].length

    Index should be available through the outer ListView if I did understand you correctly.

    ListView {
      model: yourModel.length
      
      delegate: ListView {
         model: yourModel[index].length
     }
    }
    

    Probably there is no need to write an "getLengthOfDataVector" function, if you intended to do it like this. But maybe I missed something as I don't know how you model looks like exactly.