Hi Shawn! tir. 4. feb. 2020 kl. 08:15 skrev Shawn Rutledge <[email protected]>:
> > > On 3 Feb 2020, at 10:26, Ola Røer Thorsen <[email protected]> wrote: > > > > - The biggest struggle I have with Qt currently regarding pointers is > when you share a dynamic model of QObject* to qml. Here it would actually > be useful to have shared_ptr, and I've solved this with some Q_GADGET-based > wrappers. (One could argue I should not share QObject* stuff in a model, > but putting everything in model roles does not scale well when the objects > have properties that change often, or have properties to other objects. > Hard to maintain, redundant code, no error handling in qml if a role is > mistyped, and QVariant's performance is not good.) > > Yes QVariant gets in the way. But AFAIK there is no plan to change it, > because QAIM is too entrenched. (How else can you write one model that > will work for views in both widgets and Quick?) > Yeah that makes sense. It also works just fine as long as the models don't change the values of the roles that often. What do you see as the argument against putting QObjects in models then? I > tend to think if you are creating a model for a table or a list, you can > probably store your data more compactly as an implementation detail of a > model rather than as a vector of QObject*; but OTOH if you already have > QObjects for some other reason, it’s OK to expose them, isn’t it? Or if > your data set is bounded, not too big, maybe there could even be reasons to > prefer a vector of objects? (Apropos > https://codereview.qt-project.org/c/qt/qtwebengine/+/286972 : I’m not > sure that should really be a QALM. I started thinking that it is not how I > will choose to expose a list of links to a widget-based view, so maybe I > can reconsider how to expose it to Qt Quick too. But the usual argument is > that it’s wasteful to create QObjects just for the sake of it: not items, > not widgets; and in this case they have no other reason to be QObjects. > But what else could they be? Gadgets?) > In my case I have the QObjects in a backend for the UI. They have lots of properties, some which are pointers to other objects, and others which have values that change at frequencies up to 30 Hz or so. There are also methods to call on a particular QObject instance in the model. The backend uses lots of threads to "do stuff" so QObjects, QThread, queued connection signals/slots are very powerful to get things done. Example use case - embedded device showing many live video feeds in a grid, with HUD-style overlays with dynamic metadata, and each feed gives controls on screen for manipulating camera settings. Feeds come and go "at random". The issues come when I start removing rows from the model, and delete the QObjects from those rows. Then you get all kinds of error-messages from QML in the log which I cannot live with (getting used to them will make me miss more important errors). Earlier I've also had seemingly random crashes in the qml engine, but not recently. It might have been in the earlier Qt5 versions, or because I forgot to use deleteLater instead of just deleting the objects right away. I got rid of these issues using shared_ptr in wrappers, I'll explain below. So I'm happy to use QObject* in a model, it just does not feel like it's completely supported or intended to be used this way as soon as there are rows to remove runtime. I’m also curious about your solution with Q_GADGET, since gadgets have some > shortcomings in QML (some of which I hope we will improve in Qt 6). If we > continue with the existing restriction that a gadget is always passed > between QML and C++ by value, never by pointer, then any gadget that stores > “too much” data to copy every time should have a d-pointer, right? > My Q_GADGET struct has a single member which is a std::shared_ptr to the real object, and it is registered as a qMetaType and qmlRegisterUncreatableType to really make it famous. The struct is accessible in the model as a role. Then I have a QObject-based helper class that has two properties - one which is this gadget, another with is a raw pointer to the object referenced by the gadget (smart pointer). This class is registered with qmlRegisterType. In a view delegate, I instantiate this helper-class, set the gadget property from the role name, and from there, I access the raw pointer to the real object I'm after from the raw pointer property in the helper. Now I have an object owned by QML, that will live as long as the delegate lives in the view, that holds a shared ptr to my backend object. And I have access to all the properties and methods. (hope that made sense! :P ) I've tested it a lot to make sure that it's actually the qml/js garbagecollector that triggers the deletion of the object once it's taken out of the models and nobody cares about them anymore. There is a certain lag when you take something out of a model, until the views all catch up - especially if there are animations/transitions involved. I use a custom deleter in the shared_ptr that calls deleteLater on the object from the main thread btw. It would be nice to have this done more easily somehow. Apart from that I'm really looking forward to a Qt Quick version with compile-time error messages, C++ types (no worries int64 will get rounded to double...) and no javascript runtime. Cheers, Ola
_______________________________________________ Development mailing list [email protected] https://lists.qt-project.org/listinfo/development
