Connection between asynchronous Loader in a StackLayout ?
-
Hi,
I'm working on a project where I've aStackLayout
loading asynchronously Pages usingLoader
s.
I need to communicate from the pageplantingsPage
tolocationsPage
. I imagine this could be possible using a signal onplantingsPage
but I'm not sure how to connect it. I suppose I could just connect it on my mainApplicationWindow
that 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
StackView
instead of aStackLayout
withpush
orreplace
depending 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.stackView
attached 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 aStackView
would do it, I've simplified and removed the other Pages but the idea is to have some kind ofTabView
with all the Pages being loaded only once and never being destructed. I guess this wouldn't work with aStackView
. Can aTabView
do it?
UsingLoader
s allowed to only load the Pages when they are first used, not all at the loading of theApplicationWindow
.
Does this make sense?The
plantingsPage
is aListView
. It allows to modify its Elements. When this happens I need to warn thelocationsPage
as 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 myStackLayout
orApplicationWindow
so 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); } ... }