Unsolved Handling different objects in Repeater
-
Sorry for the vague title, couldn't find a way to describe my problem.
I'm trying to find out if I should migrate my Data logger program from QWidgets to QML. I'm new to QML but already like how it works and the fact that (at least for me), it is easier to get a clear front end and back end separation. Also that it is easier to make a more user friendly UI design.
To decide wether or not I should migrate to QML I'm looking into how to solve small problems, I know I will need to implement my data logger program.
In my program I have a lot of different types of loggers. All have their own class in c++, but all inherits from the same base class, so they all share some simple functions (like get logged data). However, all of the loggers will have different properties as well they don't share. My goal is to make it possible for the user to add the logger types he needs (there can be duplicates), display the settings for each logger in the UI so he can alter the settings.
I've succesfully implemented a QAbstractListModel in c++ and connected it to QML so I can access the items in the model through a repeater. I can also add new loggers to the list. And this approach works well as long as all loggers in the list are of the same type. Then i can draw out labels and text fields, comboboxes etc, and change the properties of the individual items. All is great.
However, in my setup I will need the list of loggers to contain all kinds of different loggers, and I would like the Repeater to draw out different layouts depending on which type of logger the item is. I guess I can already hear by the name, that Repeater may not be the solution i need.
My attempts at resolving this is:
- Create a list model for each type of logger, and the use a repeater on each list. But I need the to loop through all loggers when the program is running to log data from each logger, which is tedious if I have multiple list of different kinds of loggers. Also I don't think this solution is very scalable
- I also tried putting a logger_type attribute in the base class, then in the repeater checking which type it was (using a Loader), and then trying to create a layout depending on the type. However, I could not find a way to do this, where I had access to setter and getters of the items. That is I could print out a square of differnt color depending on the logger_type, but I could not make meaningfull text fields, with the abillity to display and change settings.
I think that I may need some ideas on how to approach this, because I think I may be going in a completely wrong direction.
Hope someone can help me in the right direction
-
States and Transitions sounds pretty good. You can have your QML delegate enter different states based on stuff (variable value, expression, whatever etc)?
But that's just what immediately comes to mind... I know I myself don't fully utilize them like I could/should.
The times I have though I've come back and seen it a couple times now and thought "that's so good, don't have to really do anything at all" :-)
You probably are more suited to tell, a simple example is at:
https://qmlbook.github.io/en/ch05/index.html#states-and-transitionsreference stuff:
http://doc.qt.io/qt-5/qml-qtquick-item.html#states-prop
http://doc.qt.io/qt-5/qtquick-statesanimations-animations.html -
Thanks for your suggestion. I couldn't get it working exactly as I wanted, however, it let me to other posts where I eventually found a solution. Se working code below.
The important line was
property QtObject obj: model.item
It makes this variable available to the loaded components. It turns out that this is well described in the documentation of QML (Using loader within a view delegate). Easy enough to find, when you know it exist :-).
import QtQuick 2.6 import QtQuick.Window 2.2 import ObjectTypes 1.0 import QtQuick.Controls 1.5 Window { id: window visible: true width: 640 height: 480 title: qsTr("Hello World") Column { Repeater { model: msg delegate: Component { id: delegate Loader { property QtObject obj: model.item sourceComponent: { if(model.item.type === "A") return obj_a if(model.item.type === "B") return obj_b return obj_default } } } } } Component { id: obj_a Rectangle { width: 200 height: 60 color: "green" Text { id: text2 text: obj.type } TextField { anchors.top: text2.bottom text: obj.type onEditingFinished: obj.type = text } } } Component { id: obj_b Rectangle { width: 200 height: 90 color: "red" Text { id: text2 text: obj.type } TextField { id: text3 anchors.top: text2.bottom text: obj.type onEditingFinished: obj.type = text } TextField { anchors.top: text3.bottom text: "Test" } } } Component { id: obj_default Rectangle { width: 200 height: 60 color: "blue" Text { id: text2 text: obj.type } TextField { anchors.top: text2.bottom text: obj.type onEditingFinished: obj.type = text } } } }