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

how to connect C++ signal to QML handler



  • Hi all -

    Very elementary question here: my app emits a signal from C++ code. I'd like this to effect an update action in QML.

        Q_PROPERTY( QString synthName
                    READ GetSynthName
                    NOTIFY EventSynthNameChanged )
    

    in the QML file:

      function getSynthName() {
          var name = issViewModel.GetSynthName()
          if (name === "") {
              name = "No Synthesis Loaded"
          }
          return name;
      }
    
      Label {
          text: getSynthName()
    

    How do I connect the C++ signal to my QML? Or, is this even the correct way to do this?

    Thanks...



  • @mzimmers please provide a minimal and reproducible example


  • Moderators

    @mzimmers Simple enough but you're asking the wrong question.

    "How to I bind a qml property to a c++ property? "

    The answer, in your case:

    Label {
          text:issViewModel.synthName
    }
    

    or, if you want the "No Synthesis Loaded" check:

    Label {
          text:issViewModel.synthName === "" ? "No Synthesis Loaded" : issViewModel.synthName
    }
    

    To explicitly react to a c++ signal, look into Connections
    https://doc.qt.io/qt-5/qml-qtqml-connections.html



  • @J-Hilk beautiful...thanks! So...why is it that directly accessing the variable synthName works, but using its getter function doesn't?



  • @mzimmers said in how to connect C++ signal to QML handler:

    why is it that directly accessing the variable synthName works

    Accessing the variable "synthName" in qml will actually invoke the getter function
    https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html#exposing-properties



  • @LeLev right, I understand that...I just don't understand why a direct call to the getter didn't work for me.



  • @mzimmers have you checked the QML + C++ integration documentation?
    In particular look for using the onUserNameChanged handler.



  • @mzimmers said in how to connect C++ signal to QML handler:

    I just don't understand why a direct call to the getter didn't work for me.

    Your getSynthName() is probably not a public slot nor a Q_INVOKABLE marked function, that's why you can't call it from QML ..

    By default if you declare a Q_PROPERTY and use "Refactor" option to generate getter/setter/.., the getter is just public:
    but the setter is under public slots, so you can call the setter from qml.
    If you want to call "getSynthName()" in QML then move it under "public slots". But then :

    Label {
       text: getSynthName()
    

    this will not be updated if the value of "synthName" changes in the c++ side, you will always see the initial value of "synthName"



  • @LeLev said in how to connect C++ signal to QML handler:

    this will not refresh, you will always see the initial value of synthName.

    OK, so this is what I needed to know. So...a property will update automatically, where a reference to a function will not, right? Thanks, LeLev.



  • @mzimmers that is true.



  • @mzimmers hi again,

    sorry i misread your initial code.. i did not see that you declare getSynthName() in QML also ..

    In this case i would simply do this :

    text: issViewModel.synthName !== "" ? issViewModel.synthName : "No Synthesis Loaded"

    no need the js function.



  • Actually, I cleaned that up a little. I have a couple of utility JS functions now:

      function getNoSynthName() {
        var name =  "No Synthesis Loaded"
        return name;
      }
        function getSynthName() {
          var name = issViewModel.synthName
          if (name === "") {
              name = getNoSynthName()
          }
          return name;
      }
    

    This is the only location that uses the function in issViewModel. This allows me to do this in another area:

     StyledButton {
       visible: Utils.getSynthName() !== Utils.getNoSynthName()
    ...
    


  • @mzimmers said in how to connect C++ signal to QML handler:

    visible: Utils.getSynthName() !== Utils.getNoSynthName()

    This will be evaluated only single time, you can test it and correct me if i'm wrong.

    @mzimmers said in how to connect C++ signal to QML handler:

    Actually, I cleaned that up a little. I have a couple of utility JS functions now:
    function getNoSynthName() {
    var name = "No Synthesis Loaded"
    return name;
    }
    function getSynthName() {
    var name = issViewModel.synthName
    if (name === "") {
    name = getNoSynthName()
    }
    return name;
    }

    This is the only location that uses the function in issViewModel. This allows me to do this in another area:
    StyledButton {
    visible: Utils.getSynthName() !== Utils.getNoSynthName()
    ...

    You could replace all that by this single line that will hide the Styled Button button if the synthName == "" . And it will be reevaluated every time synthName changes...

     StyledButton {
        visible:  issViewModel.synthName
    


  • @LeLev said in how to connect C++ signal to QML handler:

    @mzimmers said in how to connect C++ signal to QML handler:

    visible: Utils.getSynthName() !== Utils.getNoSynthName()

    This will be evaluated only single time, you can test it and correct me if i'm wrong.

    It seems to update. At app startup, the button isn't visible. When I load a synthesis and return to this screen, the button is visible. The nature of the app is such that once something is loaded, it never returns to an "unloaded" state, so I can't fully test this, but it does update (at least once).

    @mzimmers said in how to connect C++ signal to QML handler:

    Actually, I cleaned that up a little. I have a couple of utility JS functions now:
    function getNoSynthName() {
    var name = "No Synthesis Loaded"
    return name;
    }
    function getSynthName() {
    var name = issViewModel.synthName
    if (name === "") {
    name = getNoSynthName()
    }
    return name;
    }

    This is the only location that uses the function in issViewModel. This allows me to do this in another area:
    StyledButton {
    visible: Utils.getSynthName() !== Utils.getNoSynthName()
    ...

    You could replace all that by this single line that will hide the Styled Button button if the synthName == "" . And it will be reevaluated every time synthName changes...

     StyledButton {
        visible:  issViewModel.synthName
    

    Not quite. When no synthesis is loaded, I need that value "No Synthesis Loaded" because I use it in two screens.



  • @mzimmers said in how to connect C++ signal to QML handler:

    Not quite. When no synthesis is loaded, I need that value "No Synthesis Loaded" because I use it in two screens.

    if you need the functions in other places then use them, but in this particular case when you write

     StyledButton {
       visible: Utils.getSynthName() !== Utils.getNoSynthName()
    

    you are hiding that button if synthName == ""

    This does the same, but is much simpler.

    StyledButton {
        visible:  issViewModel.synthName
    


  • @LeLev I suppose it's a matter of coding taste. I personally don't care to implicitly determine a boolean based on the contents of a string (or any other variable; I prefer the comparison to be made explicitly. More verbose, but (IMO) easier for the new reader to understand. I do appreciate the input, though.



  • @mzimmers said in how to connect C++ signal to QML handler:

    I prefer the comparison to be made explicitly

    you can write it in more explicit way, to me this is simpler

    StyledButton {
        visible:  issViewModel.synthName != ""
    

    than

    StyledButton {
        visible:  Utils.getSynthName() !== Utils.getNoSynthName()  
    

    @mzimmers said in how to connect C++ signal to QML handler:

    I suppose it's a matter of coding taste.

    To me it is not just a mater of taste.
    you are calling 2/3 functions where you could just write one simple js expression...

    Also because one solution will update/refresh dynamically but the other will not
    [edit] i was wrong here, actually both solution will update, as explained by @GrecKo


  • Qt Champions 2018

    @LeLev said in how to connect C++ signal to QML handler:

    Also because one solution will update/refresh dynamically but the other will not
    visible: issViewModel.synthName != "" // this will update dinamially
    visible: Utils.getSynthName() !== Utils.getNoSynthName() // this will not update dinamially.Only evaluated 1 time on component creation

    That's incorrect. Both will updated dynamically since the functions are evaluated in QML. Were the functions implemented in C++, the QML would have no way to figure out the properties dependencies but that that's not the case here.


Log in to reply