Connection between asynchronous Loader in a StackLayout ?
-
Hi,
I'm working on a project where I've aStackLayoutloading asynchronously Pages usingLoaders.
I need to communicate from the pageplantingsPagetolocationsPage. I imagine this could be possible using a signal onplantingsPagebut I'm not sure how to connect it. I suppose I could just connect it on my mainApplicationWindowthat hold theStackLayout. Could you please let me know how you'll do it.So here is my structure:
ApplicationWindow { property var navigationModel: [ { loader: plantingsPage, name: qsTr("Plantings"), iconText: "\ue0b8", component: "PlantingsPage.qml" }, { loader: locationsPage, name: qsTr("Crop Map"), iconText: "\ue55b", component: "LocationsPage.qml" }, { loader: settingsPage, name: qsTr("Settings"), iconText: "\ue616", component: "SettingsPage.qml", bindings: { "paneWidth": Math.min(600, stackLayout.width * 0.8) }} ] StackLayout { id: stackLayout property bool isLoading: children[currentIndex].status === Loader.Loading property var currentItem: children[currentIndex].item focus: true anchors.fill: parent anchors.leftMargin: largeDisplay ? drawer.width : undefined anchors.rightMargin: 0 currentIndex: navigationIndex onCurrentIndexChanged: { let index = currentIndex; if (index >= navigationModel.length) { return; } if (navigationModel[index].loader.status === Loader.Null) { if (navigationModel[index].bindings) { navigationModel[index].loader.setSource(navigationModel[index].component, navigationModel[index].bindings); } else { navigationModel[index].loader.setSource(navigationModel[index].component); } } else { navigationModel[index].loader.item.refresh(); } } Loader { id: plantingsPage; source: "PlantingsPage.qml"; asynchronous: true } Loader { id: locationsPage; asynchronous: true } Loader { id: settingsPage; asynchronous: false } }I guess I should create a dynamic connection in the else after
navigationModel[index].loader.setSource(navigationModel[index].component);
Can we do that? -
Why do each page has its own Loader?
I would use a
StackViewinstead of aStackLayoutwithpushorreplacedepending on your navigation.As for communication what do you need? What kind of info are you passing around?
I guess you can select a Crop location in your plantings page and display that in your locations page. I would let the PlantingsPage ask to show a specific crop and pass that as a paramete. In the end you'll callstackView.push("LocationsPage.qml", {crop: selectedCrop});
You could either do that directly from PlantingsPage (by accessing the StackView with theStackView.stackViewattached property) or decouple that. Maybe create a Action singleton with a signalcropSelected(string/var/QtObject crop)and connect to that signal to do the actualstackView.push. -
Why do each page has its own Loader?
I would use a
StackViewinstead of aStackLayoutwithpushorreplacedepending on your navigation.As for communication what do you need? What kind of info are you passing around?
I guess you can select a Crop location in your plantings page and display that in your locations page. I would let the PlantingsPage ask to show a specific crop and pass that as a paramete. In the end you'll callstackView.push("LocationsPage.qml", {crop: selectedCrop});
You could either do that directly from PlantingsPage (by accessing the StackView with theStackView.stackViewattached property) or decouple that. Maybe create a Action singleton with a signalcropSelected(string/var/QtObject crop)and connect to that signal to do the actualstackView.push.@GrecKo
Well I didn't implement that code. I don't think aStackViewwould do it, I've simplified and removed the other Pages but the idea is to have some kind ofTabViewwith all the Pages being loaded only once and never being destructed. I guess this wouldn't work with aStackView. Can aTabViewdo it?
UsingLoaders allowed to only load the Pages when they are first used, not all at the loading of theApplicationWindow.
Does this make sense?The
plantingsPageis aListView. It allows to modify its Elements. When this happens I need to warn thelocationsPageas it is presenting some of those Elements in another manner (TreeView). The current implementation is not ideal and rely directly on models deriving fromQSqlTableModel.
Before rethinking the architecture, I would just need to connect to a signal from plantingsPage in myStackLayoutorApplicationWindowso I could call a function onlocationsPage. Isn't this possible? The parameter would be an array of int so just a var no?
I've done something that seems to work.
Could you please let me know what you think and if there are better QML practice.MainWindow.qml:
ApplicationWindow { id: window function plantingsRefreshed(plantingsIdList){ print("MainWindow plantingsRefreshed: " + plantingsIdList); if (locationsPage.item) locationsPage.item.reloadLocationView(plantingsIdList); } ... same definition of the property navigationModel and the StackLayout defined in my first post... }PlantingsPage.qml
Page { id: page title: qsTr("Plantings") signal plantingsRefreshed(var plantingsIdList) // array of int Component.onCompleted: { page.plantingsRefreshed.connect(window.plantingsRefreshed); } }LocationsPage.qml
Page { id: page function reloadLocationView(plantingsIdList) { print("reloadLocationView: " + plantingsIdList); } ... }