0
votes

I have 2 qml files. Toolbarbutton.qml creates a button and DockWidget.qml creates a ListView. I am trying to have the button in Toolbarbutton broadcast to DockWidget that the button has been clicked. I then want to add items to my listView.

I have been trying to use a signal to establish the communication. In the Toolbarbutton.qml, I have a Rectangle item with an ID of saveButton. Under this Rectangle Item I added a signal called addSaveHistory(). I have shortened the code so its easier to see what I am doing.

Rectangle {
 id: saveButton
 width: 50
 height: 30
 border.color: "white"
 color: buttonMouseArea.containsMouse ? "grey" : "black"

//Button text
Text{
    id: buttonLabel
    anchors.centerIn: parent
    text: "Save +"
    color: "white"
}
signal addSaveHistory(string url)

 MouseArea{
    id: buttonMouseArea
    anchors.fill: parent //anchor the mousearea to the rect area

    //onClicked handles valid mouse button clicks
    onClicked: {
       addSaveHistory("Hello?") //dispatch the event

    }
}
}

In the DockWidget.qml file I have an Item that is using the Connections component. I have shorten the code so its easier to see what I am doing.

Item{
  width: 100
  height: 100
  objectName: "Save + History"

 Rectangle {
   id: rect
   anchors.fill: parent
   color: "#323232"

 Connections {
     target: saveButton //id of rectangle in ToolbarButton.qml

     onAddSaveHistory: {

       // this is never called  
     }
 }
}

I can't seem to figure out why the onAddSaveHistory is never called. I have also tried using a Loader component to load the Dockwidget.qml file into Toolbarbutton.qml and then specifically call a function in Dockwidget, but that doesn't work as well.

Do I just have the wrong idea of how the signals should work? I would greatly appreciation any guidance.

Here is my main.qml file.

import QtQuick 2.2
import Painter 1.0

import "save.js" as Save

Plugin {

//executed at startup
Component.onCompleted:{

  //add toolbar
  alg.ui.addToolBarWidget("ToolbarButton.qml")//add a button to toolbar
  alg.ui.addDockWidget("DockWidget.qml")//add dock widget

  Save.log("Incremental Save Plugin has been created")

  }
}
1

1 Answers

2
votes

First of all, realise that the signal is declared on the QML element at the root of the ToolbarButton.qml file, i.e. the Rectangle. Only the root item forms the interface for the QML element. All child elements are hidden to the outside world. So it's customary to declare the signal near the top of the file. A common ordering is:

Item {
    id: root
    property real foo: 0.0
    property alias bar: innerItem.bar
    signal baz(url location)

    Rectangle {
        id: innerItem
        property color bar: "red"
    }
}

So in this case a simple ToolbarButton.qml that declares a signal and emits it when you click in a contained MouseArea would look like this:

import QtQuick 2.3

Rectangle {
    id: root
    width: buttonLabel.width + 20
    height: buttonLabel.height + 20
    color: "steelBlue"

    // Declare signal on the button object
    signal addSaveHistory(string url)

    Text {
        id: buttonLabel
        anchors.centerIn: parent
        text: "Save +"
    }

    MouseArea {
        id: buttonMouseArea
        anchors.fill: parent
        onClicked: {
            // emit the signal
            root.addSaveHistory("Hello?")
        }
    }
}

Then a simple consumer of this signal, here just a Text element but can be anything might look like this:

import QtQuick 2.3

Text {
    id: dockWidget
    text: "Waiting for a click..."
}

But wait, you say, how does that help. Well so far there is no connection. We make that when we instantiate our reciever item. So here, the main.qml file looks like this:

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    visible: true

    // Instantiate the ToolbarButton that emits the signal when clicked
    ToolbarButton {
        id: toolbarButton
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.topMargin: 10
        anchors.leftMargin: 10
    }

    // Instantiate the DockWidget (just a Text element in this example)
    DockWidget {
        id: dockWidget
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 10
        anchors.left: parent.left
        anchors.leftMargin: 10

        // Complete the plumbing that connects the signal from item above
        // with id: toolbarButton.
        Connections {
            target: toolbarButton
            // When signal addSaveHistory is emitted,
            // replace binding above with a new one
            onAddSaveHistory: dockWidget.text = "Button was clicked"
        }
    }
}

In actual fact there is no need for the Connections element to be a child of the DockWidget. Think of the ToolbarButton and Dock widget as lego bricks that we are plumbing together at a location that has a higher level of knowledge about these items and how they should interact. If you want to though, you could wrap this up into its own more complicated custom QML component.

Furthermore, if you only have one thing caring about the signal, you don't even need the Connections element at all:

import QtQuick 2.3
import QtQuick.Window 2.2

Window {
    visible: true

    ToolbarButton {
        id: toolbarButton
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.topMargin: 10
        anchors.leftMargin: 10

        // Add signal handler directly to emitter
        onAddSaveHistory: dockWidget.text = "Button was clicked"
    }

    DockWidget {
        id: dockWidget
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 10
        anchors.left: parent.left
        anchors.leftMargin: 10
    }
}

Hope this helps.