Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Connect to the signal from an object created by stackview.push in QML



  • Hi,

    I have slot in the parent QML file which needs to be invoked from a child qml page which was created by stack view push. So I trying to emit a signal from child , which will be connected to parent as shown in the below code. This method is not working
    what is the correct method to connect this child signal to parent slot

    //BatteryInfo.qml 
    Repeater{
    	id: repeater
    	model : [ batteryInfo.bat1 , batteryInfo.bat2 , batteryInfo.bat3 ]
    
    	Battery {
    
    	    mouse_batInfo.onClicked: {
    		item = stackView.push("ChargeInfo.qml" ,{currentIndex : index})
    		// Trying to connect ChargeInfo.qml 'chrgCntrlClicked' signal to BatteryInfo.qml 'mouse_chg_control.onClicked' slot
    		item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
    	    }
    
    	    mouse_chg_control.onClicked: {
    	    
    		    if(modelData.batstatus === "charging" ){
    		        charger_controller.stopcharge()
    		    }else{
    		        charger_controller.startcharge()
    		    }
    		
    	    }
    
    	}
    }
    
    // ChargerInfo.qml
    
    Rectangle{
    
    	id: root
    	signal chrgCntrlClicked
    	Repeater{
    		model : [ batteryInfo.bat1 , batteryInfo.bat2 , batteryInfo.bat3 ]
    		ChargeInfoForm{
    			id: chargeInfoForm
    		        width: parent.width
    		        anchors.horizontalCenter: parent.horizontalCenter
    		        state: modelData.batstatus
    
    		        mouse_chg_control.onClicked: {
    		            root.chrgCntrlClicked
    		        }
    		}
    
    	}
    }
    

    Regards,
    James A



  • Hi All,

    I have simplified the above code and added it below . Any way to connect the child signal to parent slot ?

    // BatteryInfo.qml file
    Rectangle {
    
    	    mouse_batInfo.onClicked: {
    		item = stackView.push("ChargeInfo.qml")
    		// Trying to connect ChargeInfo.qml 'chrgCntrlClicked' signal to BatteryInfo.qml 'mouse_chg_control.onClicked' slot
    		item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
    	    }
    
    	    mouse_chg_control.onClicked: {
    		   console.log("Button clicked")	
    	    }
    
    	}
    	
    // ChargerInfo.qml file 
    Rectangle{
    
    	id: root
    	signal chrgCntrlClicked
    	ChargeInfoForm{
    			
    		        mouse_chg_control.onClicked: {
    		            root.chrgCntrlClicked
    		        }
    		      }
             }
    

    Regards,
    James A



  • Which portion of the provided example is not working?
    What does it do that is not expected, or not do that is expected?

    Edit: Or are you just looking for the documentation page Connecting signals to methods and signals?



  • Hai @jeremy_k

    item = stackView.push("ChargeInfo.qml")
    item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
    

    connection between signals and slots is not working , getting error message
    Error: Invalid write to global property "item"

    Expected result : when mouse is clicked in the ChargeInfo.qml file it should emit chrgCntrlClicked signal and call the slot in batteryinfo.qml file which prints message "button clicked"

    Is something wrong in connecting the signals and slots in the above example ?

    Regards,
    James A



  • @James-A said in Connect to the signal from an object created by stackview.push in QML:

    Hai @jeremy_k

    item = stackView.push("ChargeInfo.qml")
    item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
    

    connection between signals and slots is not working , getting error message
    Error: Invalid write to global property "item"

    The error message is telling you that assigning to item is invalid, and is throwing an exception. The line after the assignment isn't executed. That's a limitation of the QML engine. item needs to be declared as a local var, or a non-global property.
    https://doc.qt.io/qt-5/qtqml-javascript-hostenvironment.html#javascript-environment-restrictions



  • Hai @jeremy_k

    I declared the "item" as local variable as shown below, now the error does not appear , but the "mouse_chg_control.onClicked" slot in BatteryInfo.qml file is not called on emitting the "chrgCntrlClicked" in ChargerInfo.qml file.

    Added the updated code below

    "BatteryInfo.qml" 
    
    Rectangle {
    
        Button {
            id: mouse_batInfo
            x: 207
            y: 176
            text: qsTr("Load")
            onClicked: {
                var item = stackView.push("qrc:/ChargerInfo.qml")
                item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
            }
        }
    
        Button {
            id: mouse_chg_control
            x: 216
            y: 277
            text: qsTr("Button")
    
            onClicked: {
                console.log("Button clicked")
            }
        }
    
    }
    
    "ChargerInfo.qml"
    
    Rectangle{
    
        id: root
        signal chrgCntrlClicked
    
        Button {
            id: button
            x: 112
            y: 129
            text: qsTr("Button")
            onClicked: {
                root.chrgCntrlClicked
            }
        }
    
    
    }
    
    "main.qml"
    
    ApplicationWindow {
    
        width: 640
    
        height: 480
    
        visible: true
    
        title: qsTr("Hello World")
    
        StackView{
          id : stackView
          initialItem: "qrc:/BatteryInfo.qml"
          anchors.fill: parent
        }
    
    }
    


  • @James-A said in Connect to the signal from an object created by stackview.push in QML:

                root.chrgCntrlClicked
    

    This is missing () to invoke the signal.

    As a matter of personal taste, I prefer using Connections over imperative javascript to manage connection to a fixed number of dynamically created objects. Both versions of StackView have a currentItem that points to the top of the stack.



  • Hi @jeremy_k ,

    Sorry for the delayed reply , the root.chrgCntrlClicked() code helped me to fix the issue. Now I am trying with Repeaters as shown in the below code.

    // BatteryInfo qml file

    RowLayout {
                anchors.fill: parent
                Repeater{
                    id: repeater
                    model : [ batteryInfo.bat1 , batteryInfo.bat2 , batteryInfo.bat3 ]
    
                    Battery {
    
                        Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
    
                        mouse_batInfo.onClicked: {
                            var item = stackView.push("ChargeInfo.qml")
    			item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
                        }
    
                        mouse_chg_control.onClicked: {
                           console.log("Button is clicked")                 
                        }
    
    
    
                    }
                }
            }
    

    // ChargeInfo.qml file

     signal chrgCntrlClicked
     
     Repeater{
    
                model : [ batteryInfo.bat1 , batteryInfo.bat2 , batteryInfo.bat3 ]
    
                // loader is used keep only current item on the screen and load the other UI dynamically on swiping
                Loader {
                    active: SwipeView.isCurrentItem
                    sourceComponent: Rectangle{
                        ChargeInfoForm {
                            id: chargeInfoForm
    
                            mouse_chg_control.onClicked: {
                                 root.chrgCntrlClicked()
                            }
    
                            txt_batName.text: "Battery " + (index + 1)
    
                        }
                    }
                }
    
            }
    

    Totally three Items will be created on the UI. Whenever the button is clicked the mouse_chg_control.onClicked function gets called, which has to call the corresponding slot in the Battery info qml file

    But When I click the button in the ChargeInfo.qml file I get error "Error: Insufficient arguments".
    What is proper way to connect the ChargeInfo.qml signal to corresponding BatteryInfo.qml slots ?



  • @James-A Can you convert the code into a self-contained minimal example? Its easier to spot and fix errors if the code is otherwise executable.



  • Hi @jeremy_k ,

    I was able to fix the "Error: Insufficient arguments". error. Now I need some idea on how to connect the signal from an Item in the child to parent item

    The BatteryInfo.qml (parent) and ChargerInfo.qml (child) contains 3 items. In child page whenever a button is clicked under an item the corresponding parent item button needs to be called. This is happening with the present code added below.
    But the problem is when I swipe and click the Items button in the child page the corresponding parent item button is not called

    Please execute this code to see the behaviour

    // main.qml

    import QtQuick 2.4
    import QtQuick.Window 2.4
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
    
        width: 700
    
        height: 480
    
        visible: true
    
        title: qsTr("Hello World")
    
        StackView{
          id : stackView
          initialItem: "qrc:/BatteryInfo.qml"
          anchors.fill: parent
        }
    
    }
    

    //Charge.qml

    import QtQuick 2.4
    import QtQuick.Controls 2.3
    
    Rectangle{
    
        id: root
        width: 235
        height: 370
    
        property alias mouse_chg_control: mouse_chg_control
        property alias text1: text1
    
        Button {
            id: mouse_chg_control
            x: 87
            y: 216
            text: qsTr("Button")
    
        }
    
        Text {
            id: text1
            x: 118
            y: 116
            text: qsTr("Text")
            font.pixelSize: 12
        }
    
    
    }
    

    // Battery.qml

    import QtQuick 2.2
    import QtQuick.Shapes 1.2
    import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.0
    
    Rectangle {
        width: 235
        height: 370
        property alias txt_name: txt_name
        property alias mouse_batInfo: mouse_batInfo
        property alias mouse_chg_control: mouse_chg_control
    
        MouseArea {
            id: mouse_batInfo
            anchors.fill: parent
        }
    
        Button {
            id: mouse_chg_control
            x: 59
            y: 228
            width: 100
            height: 37
            text: qsTr("Button")
        }
    
        Text {
            id: txt_name
            x: 97
            y: 121
            text: qsTr("Text")
            font.pixelSize: 12
        }
    }
    

    //BatteryInfo.qml

    import QtQuick 2.4
    import QtQuick.Controls 2.3
    import QtQuick.Layouts 1.2
    
    Item {
    
        RowLayout {
            anchors.fill: parent
            Repeater{
                id: repeater
                model : 3
    
                Battery {
    
                    Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
    
                    txt_name.text: index
    
                    mouse_batInfo.onClicked: {
                        var item = stackView.push("qrc:/ChargeInfo.qml" ,{currentIndex : index})
                        item.chrgCntrlClicked.connect(mouse_chg_control.onClicked)
                    }
    
                    mouse_chg_control.onClicked: {
                        console.log("button clicked : " + index )
                    }
    
                }
            }
        }
    
    }
    
    

    // ChargeInfo.qml

    import QtQuick 2.4
    import QtQuick.Controls 2.3
    import QtQuick.Layouts 1.2
    
    Item {
    
        id : chargeinfo
        property alias currentIndex : swipeView.currentIndex
    
        PageIndicator {
            id: indicator
            x: 485
            y: 453
            width: 50
            z: 1
            anchors.horizontalCenterOffset: 8
            anchors.horizontalCenter: swipeView.horizontalCenter
            currentIndex: swipeView.currentIndex
            count: swipeView.count
        }
    
        signal chrgCntrlClicked
    
        SwipeView{
            id: swipeView
            width: 650
    
            anchors.left: parent.left
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.horizontalCenterOffset: 0
            anchors.leftMargin: 0
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottomMargin: 0
            anchors.topMargin: 71
    
            Repeater{
    
                model : 3
    
                // loader is used keep only current item on the screen and load the other UI dynamically on swiping
                Loader {
                    active: SwipeView.isCurrentItem
                    sourceComponent:
                        Rectangle{
                        Charger {
    
                            width: parent.width
                            anchors.horizontalCenter: parent.horizontalCenter
    
                            text1.text: index
    
                            mouse_chg_control.onClicked: {
                                chargeinfo.chrgCntrlClicked()
                            }
    
                        }
                    }
                }
            }
        }
    
        Button{
    
            text: "BACK"
    
            onClicked: {
    
                if (stackView.depth > 1) {
                    stackView.pop()
                }
    
            }
        }
    
    }
    
    


  • Lets start from a simpler example:

    main.qml:

    import QtQuick 2.4
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        width: 700
        height: 480
        visible: true
    
        StackView{
          id : stackView
          initialItem: A{}
          anchors.fill: parent
        }
    
        Connections {
            target: stackView.currentItem
            function onClicked() { console.log("got a click"); }
        }
    }
    

    A.qml:

    import QtQuick 2.2
    import QtQuick.Controls 2.2
    
    Rectangle {
        id: root
        signal clicked()
        Button {
            anchors.centerIn: parent
            text: "button"
            onClicked: root.clicked()
        }
    }
    


  • Hai @jeremy_k ,

    Using target: stackView.currentItem was a good idea. I tried running , its working fine.
    But if there are A , B , C (child) qml files. and three onClicked slots for each child in main qml file , how to connect corresponding signals from child to main qml file

    child.qml || main.qml

    A.qml --> onAClicked()
    B.qml --> onBClicked()
    C.qml --> onCClicked()



  • @James-A said in Connect to the signal from an object created by stackview.push in QML:

    But if there are A , B , C (child) qml files. and three onClicked slots for each child in main qml file , how to connect corresponding signals from child to main qml file

    Do you expect to interact with all three at the same time, or only the item currently at the top of the stack?



  • @jeremy_k

    Only with one item which is currently at the top of the stack



  • @James-A said in Connect to the signal from an object created by stackview.push in QML:

    @jeremy_k

    Only with one item which is currently at the top of the stack

    Then there's no need to deal each item individually. As long as all three use signals with the same name, Connections { target: stackView.currentItem } will rebind to the new currentItem, and make the connection.



  • @jeremy_k

    I updated the BatteryInfo.qml class as shown below

    import QtQuick 2.4
    import QtQuick.Controls 2.3
    import QtQuick.Layouts 1.2
    
    Item {
    
        Connections {
            target: stackView.currentItem
            function onChrgCntrlClicked()
            { console.log("got a click");
              battery.mouse_chg_control.clicked()
            }
        }
    
        RowLayout {
            anchors.fill: parent
            Repeater{
                id: repeater
                model : 3
    
                Battery {
                    id : battery
                    Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
    
                    txt_name.text: index
    
                    mouse_batInfo.onClicked: {
                        stackView.push("qrc:/ChargeInfo.qml" ,{currentIndex : index})
                    }
    
                    mouse_chg_control.onClicked: {
                        console.log("button clicked : " + index )
                    }
    
                }
            }
        }
    
    }
    
    

    I was getting the below error message

    qrc:/BatteryInfo.qml:7:5: QML Connections: Detected function "onChrgCntrlClicked" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
    qml: got a click
    qrc:/BatteryInfo.qml:11: ReferenceError: battery is not defined



  • @James-A said in Connect to the signal from an object created by stackview.push in QML:

    @jeremy_k

    I updated the BatteryInfo.qml class as shown below
    [...]

    There is nothing with the id stackView here. It's too confusing for me to attempt to stitch together code from previous posts and infer missing portions. Please use examples that are both simple and complete. Remove everything that is not related to the problem at hand, and include everything that a reader would need to copy and paste to achieve the same result.

    I was getting the below error message

    qrc:/BatteryInfo.qml:7:5: QML Connections: Detected function "onChrgCntrlClicked" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
    qml: got a click
    qrc:/BatteryInfo.qml:11: ReferenceError: battery is not defined

    These are both generally straight forward errors. Is there a chrgCntrlClicked signal associated with stackView.currentItem? Is it a signal of a child item that needs to be propagated, or is there a typo? Setting the ignoreUnknownSignals property to allow for transitory states that lack the signal can help to silence irrelevant warnings.

    Is there a battery property or variable in scope? Ids in a Repeater or ListView delegate are not meaningful outside of a delegate instance. The example above has 3 instances of Battery called battery created in a Repeater. Which one is battery supposed to reference?


Log in to reply