Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Connection between asynchronous Loader in a StackLayout ?
Forum Updated to NodeBB v4.3 + New Features

Connection between asynchronous Loader in a StackLayout ?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
3 Posts 2 Posters 965 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mbruelM Offline
    mbruelM Offline
    mbruel
    wrote on last edited by
    #1

    Hi,
    I'm working on a project where I've a StackLayout loading asynchronously Pages using Loaders.
    I need to communicate from the page plantingsPage to locationsPage. I imagine this could be possible using a signal on plantingsPage but I'm not sure how to connect it. I suppose I could just connect it on my main ApplicationWindow that hold the StackLayout . 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?

    1 Reply Last reply
    0
    • GrecKoG Offline
      GrecKoG Offline
      GrecKo
      Qt Champions 2018
      wrote on last edited by
      #2

      Why do each page has its own Loader?

      I would use a StackView instead of a StackLayout with push or replace 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 call stackView.push("LocationsPage.qml", {crop: selectedCrop});
      You could either do that directly from PlantingsPage (by accessing the StackView with the StackView.stackView attached property) or decouple that. Maybe create a Action singleton with a signal cropSelected(string/var/QtObject crop) and connect to that signal to do the actual stackView.push.

      mbruelM 1 Reply Last reply
      0
      • GrecKoG GrecKo

        Why do each page has its own Loader?

        I would use a StackView instead of a StackLayout with push or replace 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 call stackView.push("LocationsPage.qml", {crop: selectedCrop});
        You could either do that directly from PlantingsPage (by accessing the StackView with the StackView.stackView attached property) or decouple that. Maybe create a Action singleton with a signal cropSelected(string/var/QtObject crop) and connect to that signal to do the actual stackView.push.

        mbruelM Offline
        mbruelM Offline
        mbruel
        wrote on last edited by mbruel
        #3

        @GrecKo
        Well I didn't implement that code. I don't think a StackView would do it, I've simplified and removed the other Pages but the idea is to have some kind of TabView with all the Pages being loaded only once and never being destructed. I guess this wouldn't work with a StackView. Can a TabView do it?
        Using Loaders allowed to only load the Pages when they are first used, not all at the loading of the ApplicationWindow.
        Does this make sense?

        The plantingsPage is a ListView. It allows to modify its Elements. When this happens I need to warn the locationsPage as it is presenting some of those Elements in another manner (TreeView). The current implementation is not ideal and rely directly on models deriving from QSqlTableModel.
        Before rethinking the architecture, I would just need to connect to a signal from plantingsPage in my StackLayout or ApplicationWindow so I could call a function on locationsPage. 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);
            }
        ...
        }
        
        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved