One QML component to be used by multiple C++ controller classes
-
I have an embedded device that's pretty slow and i want to speed up loading of windows. Let's say I have a complex QML Window that takes some time to load on my embedded device:
ComplexWindow.qml:
@
Rectangle {
property string title
// other stuff that takes some time to load.
}
@I have one main qml file that has several ComplexWindows that are visible by toggling the visible flag:
Main.qml:
@
ComplexWindow { id: inputWindow; title: myInputWindowCppObj.title; visible: myInputWindowCppObj.visible etc }
ComplexWindow { id: inputSpecialWindow; title: myInputSpecialWindowCppObj.title; visible: ContactListController.visible etc }
// etc etc
@All my ComplexWindows have the same user interface structure but are used differently by the C++ controller classes. To decrease load times I want to have ONE ComplexWindow in my main qml file and let the C++ controller classes share that one instance of ComplexWindow. Only one ComplexWindow is visible at one time so it could be shared.
I want to control ONE QML component by several C++ controller classes. Currently I connect the QML ComplexWindows instances and the C++ controller classes by using the setContextProperty method. But I want only one instance of ComplexWindow being used by all my c++ controller classes.
Can I somehow (without showing errors in the log):
- Connect the QML/C++ binding when a c++ controller class is activated. For example a user opens the application menu and decides to open a certain window. Then a c++ controller classes is called and the QML/C++ binding is set. So now the c++ controller classes can control the QML ComplexWindow. When the user decides to leave the window the c++ controller class unbinds itself from QML ComplexWindow instance.
I have noticed that when in the QML files a property is being binded to a none existing c++ "slot" i receive errors that it cannot bind the property. When I want to share my QML ComplexWindow instance by several c++ controller classes I will have the problem of properties not being binded.
Does anyone have a suggestion?
-
I'm not entirely certain that I've understood correctly (regarding your wish to reuse a single component; I personally would probably use a Loader and then set enabled and visible to false when not using one, but perhaps that doesn't work in your use case) but to set up dynamic bindings and signal connections, you can use the Binding and Connections elements, respectively. You can dynamically retarget those, and so you can do it at runtime.
Cheers,
Chris. -
My apologies for this late reply!
bq. I personally would probably use a Loader and then set enabled and visible to false when not using one, but perhaps that doesn’t work in your use case) bq.
I already use loaders to load / unload QML files but my hardware device is pretty slow so loading/parsing the files takes a long time. This is irritating for the user because he has to wait for a window to be visible...
Now I already have a lot of QML Windows and QML controllers so I thought maybe I need to limit the nr of QML windows to one. Then let a C++ controller set the contextproperties to that qml window whenever it's used. This way I don't need to load a QML file.
bq. You can dynamically retarget those, and so you can do it at runtime. bq.
How do you retarget those things from C++? Currently I use the setContextProperty to connect C++/QML but how do i unset a contextproperty? So when a controller is done controlling the QML window how do you "unset" the contextproperties? I tried to set it to null (setContextProperty("mycppObj.test", NULL) but I get an error.
-
I may have completely misunderstood what you are attempting to do with the controller, but lets say you want to dynamically set up bindings when some context properties change:
@
Item {
id: root
width: 300
height: 300property Item currentWindow Binding { id: widthBinding target: currentWindow property: "x" value: (root.width / 2) // or whatever bindings you want to be dynamic } onCurrentWindowChanged: widthBinding.target = currentWindow // might not be required
}
@I just mean that as you dynamically change whichever window is your current window, you can create dynamic bindings which will ensure that your ui elements are placed correctly.
Similarly, for signal connections, you can use the Connections element.
Cheers,
Chris. -
That's not completely what i'm looking for:
QML:
@
Window {
visible: myCppObj.visible
// other bindings
}
@C++ base class for window:
@
class BaseWindow : public QObject {
Q_OBJECT
Q_PROPERTY(bool visible READ Visible NOTIFY VisibleChanged)
public:
MyWindow::MyWindow() {}
void SetVisible(....);
// signals
// slots
@C++ derived class:
@
class DerivedWindow : public QObject {
public:
DerivedWindow::DerivedWindow() {}
void RegisterQml() { mDeclarativeContext->setContextProperty("myCppObj",this); }
void DereigsterQml() ??????
}
@C++ derived class two:
@
class DerivedTwoWindow : public QObject {
public:
DerivedTwoWindow::DerivedTwoWindow() {}
void RegisterQml() { mDeclarativeContext->setContextProperty("myCppObj",this); }
void DereigsterQml() ??????
@Ok, so now I have one QML window and two C++ controller classes that want to control the QML window (not simultanously).
User opens first window and closes it:
@
DerivedWindow lWIndow;
lWindow.Register();
lWIndow.Show(); // Show QML window
lWindow.Deregister(); // Decouple QML/C++ binding
@Then user opens second window:
@
DerivedTwoWindow lWindow2;
lWindow2.Register();
lWindow2.Show();
lWindow2.Deregister();
@ -
[quote author="bkamps" date="1344230102"]So when a controller is done controlling the QML window how do you "unset" the contextproperties? I tried to set it to null (setContextProperty("mycppObj.test", NULL) but I get an error.
[/quote]What error were you seeing? Are you wanting to unset myCppObj as a whole, or just some of it's sub properties? Note that if you are unsetting the object itself, the QML would need conditional checks to prevent errors, e.g. checks like:
@visible: myCppObj ? myCppObj.visible : false@
Easier might be a DummyWindow that could be set in DeregisterQml(), e.g.
@void UnregisterQml() { mDeclarativeContext->setContextProperty("myCppObj",dummyWindow); }@
This "window" would have sensible defaults for the properties when there was no real window controlling the QML, and would prevent the need for the conditional checks in the QML.
Does that make sense for what you are trying to do?
Regards,
Michael -
bq. What error were you seeing? Are you wanting to unset myCppObj as a whole, or just some of it’s sub properties? Note that if you are unsetting the object itself, the QML would need conditional checks to prevent errors, e.g. checks like:
bq.
I am setting the properties. When i do a setContextProperty("mycppObj", null) I get the following error:
@TypeError: Result of expression 'model' [null] is not an object.@
This is because I set the object to null and have to do the null check in qml like you showed me... I guess I will get this thing to work.
Firstly I will try to get two controllers to control one QML window (independently) by resetting the C++/QML bindings.