dealing with model polymorphism in QML
-
Hi all -
I have a (C++) model that implements a list of objects (actually pointers to objects, but that's probably not important here). The objects are of various subclasses, all inherited from the same parent. Super short example:
enum Category { CATEGORY_UNKNOWN, CATEGORY_PUMP, CATEGORY_HEATER, ... } struct Equipment { QUuid m_uuid = QUuid(); Category m_category = CATEGORY_UNKNOWN; ... } struct Pump : public Equipment { int horsepower; ... }
And somewhere in the code, instances of Pump have their category changed to CATEGORY_PUMP.
In QML, I have a GridView that uses the list as its model. My problem is how to implement a delegate that only attempts to do something with "horsepower" when the category is CATEGORY_PUMP?
Thanks...
-
@mzimmers I am sorry - I have only used this feature once myself so I don't have a huge amount of experience of it. In my case, the
role
was assigned to a role name that I expose from my model. The documentation implies that alternatively one may specify the name of a property of the model. As I understand it, that is what you are doing, but I haven't tried that approach. -
@Bob64 interesting...another part of the QML world I'd never seen.
It looks like it will work with a GridView instead of a TableView, so that's good news for me. If I want my DelegateChooser to use the category property of my struct, how do I code this?
Here's a little more of my C++:
struct Equipment { QUuid m_uuid = QUuid(); Category m_category = CATEGORY_UNKNOWN; // from an enum Q_PROPERTY (Category category MEMBER m_category) ... } struct Pump : public Equipment { int horsepower; ... }
There's also a model that maintains a list of these.
Here's the QML I tried, just a test:
GridView { model: equipmentProxyModel DelegateChooser { role: "category" DelegateChoice { roleValue: 1; ItemDelegate { Rectangle { height: 20; width: 20; color: 'blue' }}} } ...
It doesn't display the rectangle. It looks like I'm somehow missing a link between the "category" property in my struct, and the role that the DelegateChoice expects. Can you tell me what might be missing?
Thanks...
-
@mzimmers I am sorry - I have only used this feature once myself so I don't have a huge amount of experience of it. In my case, the
role
was assigned to a role name that I expose from my model. The documentation implies that alternatively one may specify the name of a property of the model. As I understand it, that is what you are doing, but I haven't tried that approach. -
-
@GrecKo OK, I fixed that, and now it's working, but only for members of the base class:
GridView { model: equipmentProxyModel delegate: chooser DelegateChooser { id: chooser role: "category" DelegateChoice { roleValue: EquipmentNS.CATEGORY_UNKNOWN; ItemDelegate { height: 20 width: 20 Label { text: uuid } } } DelegateChoice { roleValue: EquipmentNS.CATEGORY_VSP; ItemDelegate { height: 20 width: 20 Label { text: horsepower } // unrecognized. } }
I understand why it's failing (the parent class doesn't have that member), but I'm not sure what to do about it. Is there a way to fix this in the QML, or do I need to refine my data()/setdata() functions in my model?
-
@mzimmers This doesn't have to do with classes. You are trying to access the roles of your model. Does your model has a "horsepower" role?
I guess what you want to do is provide an object role just returning a pointer. And then accessing properties of that object in the delegate.
Let's call it "equipment", you could then access the horsepower in the delegate withtext: equipment.horsepower
. -
@GrecKo thanks for the suggestion. I already have a "completeObject" role which returns the entire object.
I realize this isn't a QML question, but in your opinion, is it better to keep all the roles and role processing in the model code, or should I build this into the subclasses? I was thinking of the latter, just to prevent the model code from becoming huge if nothing else, but I'm running into design problems with that approach. What do experienced model builders do in this situation?
Thanks...
-
-