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. QML TreeView - how to apply delegate to certain items in the tree?
QtWS25 Last Chance

QML TreeView - how to apply delegate to certain items in the tree?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qmltreeviewmodel-viewdelegate
9 Posts 3 Posters 9.6k 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.
  • HaithamH Offline
    HaithamH Offline
    Haitham
    wrote on last edited by Haitham
    #1

    Hello guys,

    I'm a newbie at QML and QT so please bear with me,
    I've created a model in C++ for a TreeView QML type through which I can view the model and apply a suitable delegate for my items.

    so what I need to do is to have 2 icons in front of each child item except for "Objects detected count" and "Objects in pallet count" and the parent items (i.e. communication status,...etc.) instead of having the icons in front of each item. The tree is shown below

    alt text

    Here is the delegate file

    MyTreeDelegate.qml

    import QtQuick 2.0
    import QtQuick.Controls 1.4
    
    Component   //must wrap rectangle inside a component QML type to be called from a different file
    {
        Rectangle
        {
            id:baseRec
            color: "transparent"
            //    color: ( styleData.row % 2 == 1 ) ? "white" : "#60e6dd"
            height: 5
            //    border.color: "black"
            //    border.width: 1
            
            MouseArea
            {
                anchors.fill: parent
    
                onClicked:
                {
                    console.log("row: ",styleData.row)
                    console.log("column: ",styleData.column)
                    console.log("index: ",styleData.index)
                }
            }
            
            Text
            {
                anchors.verticalCenter: parent.verticalCenter
                text: styleData.value === undefined ? "" : styleData.value
                // The branches don't have a description_role so styleData.value will be undefined
            }
    
            Image
            {
                height: baseRec.height
                width: height
                id:rightImage
                source: "images/RedOff.png"
                anchors
                {
                    verticalCenter:baseRec.verticalCenter
                    right:baseRec.right
                }
            }
    
            Image
            {
                id:leftImage
                height: baseRec.height
                width: height
                source: "images/GreenOff.png"
                anchors
                {
                    verticalCenter:baseRec.verticalCenter
                    right:rightImage.left
                }
            }
        }
    }
    
    

    main.qml

    import QtQuick 2.0
    import QtQuick.Controls 1.4
    import QtQuick.Controls.Styles 1.4
    import QtQuick.Window 2.2
    import MyTreeModel 1.0  //from qmlRegister in C++ code
    
    Rectangle
    {
        id:mainRec
        MyTreeModel
        {
            id: theModel
        }
    
        MyTreeDelegate
        {
            id: theDelegate
        }
    
        TreeView
        {
            id: treeView
            style: TreeViewStyle    //for styling the tree
            {
                backgroundColor: "white"
                alternateBackgroundColor:"white"
                //branch delegates are used for delegating the arrow on the left
            }
            //think of what to do on a double click or single click
            //think of how to delegate only specific children
    
            headerVisible: false    //to hide the header
            anchors.fill: mainRec    //to fill rectangle
    
            model: theModel
    
            itemDelegate: theDelegate
    
            onItemDelegateChanged:
            {
    //        console.log("current index: ", index)
            }
    
            TableViewColumn
            {
                role: "name_role"
                title: "Status"
            }
        }
    }
    
    

    I've tried using styleData.row and styleData.index but I can't figure out how to use them to my advantage.

    Thanks for reading through all of this.

    E 1 Reply Last reply
    0
    • 6thC6 Offline
      6thC6 Offline
      6thC
      wrote on last edited by
      #2

      Make your delegate react to states. This might help get you moving again:
      https://qmlbook.github.io/en/ch05/index.html#states-and-transitions

      I also use ternary expressions (not states) to do things such as:

      Rectangle{
              color               : PathView.isCurrentItem ? color : currentColor; //"black" : "red"
      

      I don't see why you couldn't add a property:

      TreeView { 
      id: treeView;
      property bool activeComms: true;
      

      and in your delegate:

      source: parent.activeComms === false ? "images/GreenOff.png" : "images/RedOff.png";
      

      or

      source: parent.activeComms ? "images/GreenOn.png" : "images/RedOn.png";
      
      HaithamH 1 Reply Last reply
      0
      • HaithamH Haitham

        Hello guys,

        I'm a newbie at QML and QT so please bear with me,
        I've created a model in C++ for a TreeView QML type through which I can view the model and apply a suitable delegate for my items.

        so what I need to do is to have 2 icons in front of each child item except for "Objects detected count" and "Objects in pallet count" and the parent items (i.e. communication status,...etc.) instead of having the icons in front of each item. The tree is shown below

        alt text

        Here is the delegate file

        MyTreeDelegate.qml

        import QtQuick 2.0
        import QtQuick.Controls 1.4
        
        Component   //must wrap rectangle inside a component QML type to be called from a different file
        {
            Rectangle
            {
                id:baseRec
                color: "transparent"
                //    color: ( styleData.row % 2 == 1 ) ? "white" : "#60e6dd"
                height: 5
                //    border.color: "black"
                //    border.width: 1
                
                MouseArea
                {
                    anchors.fill: parent
        
                    onClicked:
                    {
                        console.log("row: ",styleData.row)
                        console.log("column: ",styleData.column)
                        console.log("index: ",styleData.index)
                    }
                }
                
                Text
                {
                    anchors.verticalCenter: parent.verticalCenter
                    text: styleData.value === undefined ? "" : styleData.value
                    // The branches don't have a description_role so styleData.value will be undefined
                }
        
                Image
                {
                    height: baseRec.height
                    width: height
                    id:rightImage
                    source: "images/RedOff.png"
                    anchors
                    {
                        verticalCenter:baseRec.verticalCenter
                        right:baseRec.right
                    }
                }
        
                Image
                {
                    id:leftImage
                    height: baseRec.height
                    width: height
                    source: "images/GreenOff.png"
                    anchors
                    {
                        verticalCenter:baseRec.verticalCenter
                        right:rightImage.left
                    }
                }
            }
        }
        
        

        main.qml

        import QtQuick 2.0
        import QtQuick.Controls 1.4
        import QtQuick.Controls.Styles 1.4
        import QtQuick.Window 2.2
        import MyTreeModel 1.0  //from qmlRegister in C++ code
        
        Rectangle
        {
            id:mainRec
            MyTreeModel
            {
                id: theModel
            }
        
            MyTreeDelegate
            {
                id: theDelegate
            }
        
            TreeView
            {
                id: treeView
                style: TreeViewStyle    //for styling the tree
                {
                    backgroundColor: "white"
                    alternateBackgroundColor:"white"
                    //branch delegates are used for delegating the arrow on the left
                }
                //think of what to do on a double click or single click
                //think of how to delegate only specific children
        
                headerVisible: false    //to hide the header
                anchors.fill: mainRec    //to fill rectangle
        
                model: theModel
        
                itemDelegate: theDelegate
        
                onItemDelegateChanged:
                {
        //        console.log("current index: ", index)
                }
        
                TableViewColumn
                {
                    role: "name_role"
                    title: "Status"
                }
            }
        }
        
        

        I've tried using styleData.row and styleData.index but I can't figure out how to use them to my advantage.

        Thanks for reading through all of this.

        E Offline
        E Offline
        Eeli K
        wrote on last edited by
        #3

        @Haitham I haven't used Controls 1 but it looks like you can simply add the visible property value to Image elements:

        Image
        {
            visible: !(styleData.value === "Objects detected count" || styleData.value === "Palletizing Status" || [etc...])
        

        Or instead of text values try those styleData.row, styleData.index or something else which might work.

        HaithamH 1 Reply Last reply
        0
        • E Eeli K

          @Haitham I haven't used Controls 1 but it looks like you can simply add the visible property value to Image elements:

          Image
          {
              visible: !(styleData.value === "Objects detected count" || styleData.value === "Palletizing Status" || [etc...])
          

          Or instead of text values try those styleData.row, styleData.index or something else which might work.

          HaithamH Offline
          HaithamH Offline
          Haitham
          wrote on last edited by Haitham
          #4

          @Eeli-K That's what I wrote at the end of the post bro

          The problem with styleData.row as far as I can tell that it depends if the parent items are expanded or not.

          for instance, "Vision status" might return 1 and might return 3 depending if "Communication status" is expanded or not.

          Unfortunately, I don't know how to benefit from styleData.index though it would come in handy later on.

          I will keep you posted if I've figured out a solution to this problem. Thanks for your help

          Update:

          using visible with styleData.depth===0 made the icons disappear next to the items

          styleData.row, as I mentioned earlier, depends if the parent items are expanded so it's pretty useless and I've tested it.

          1 Reply Last reply
          0
          • 6thC6 6thC

            Make your delegate react to states. This might help get you moving again:
            https://qmlbook.github.io/en/ch05/index.html#states-and-transitions

            I also use ternary expressions (not states) to do things such as:

            Rectangle{
                    color               : PathView.isCurrentItem ? color : currentColor; //"black" : "red"
            

            I don't see why you couldn't add a property:

            TreeView { 
            id: treeView;
            property bool activeComms: true;
            

            and in your delegate:

            source: parent.activeComms === false ? "images/GreenOff.png" : "images/RedOff.png";
            

            or

            source: parent.activeComms ? "images/GreenOn.png" : "images/RedOn.png";
            
            HaithamH Offline
            HaithamH Offline
            Haitham
            wrote on last edited by Haitham
            #5

            @6thC
            So I've followed your advice and checked states and they are pretty nice.

            I've made a very dummy program to test them and they worked well!

            alt text

            the application consisted of the following code (not the whole code)

                    Image
                    {
                        id: red
                        source: "images/RedOff.png"
                        anchors
                        {
                            centerIn: root
                        }
                    }
            
                    Image
                    {
                        id: green
                        source: "images/GreenOff.png"
            
                        anchors
                        {
                            left:red.right
                            verticalCenter:root.verticalCenter
                        }
                    }
            
                    states:
                        [
                        State
                        {
                            name: "GreenOn"
                            PropertyChanges { target: green; source:"images/GreenOn.png"}
                            PropertyChanges { target: red; source:"images/RedOff.png" }
                        },
            
                        State
                        {
                            name: "RedOn"
                            PropertyChanges { target: green; source:"images/GreenOff.png"}
                            PropertyChanges { target: red; source:"images/RedOn.png" }
                        },
            
                        State
                        {
                            name: "BothOff"
                            PropertyChanges { target: green; source:"images/GreenOff.png"}
                            PropertyChanges { target: red; source:"images/RedOff.png" }
                        }
                    ]
            
                    //Control buttons
                    Row
                    {
                        spacing: 5
            
                        Button
                        {
                            id: btnOn
                            text: "On"
                            onClicked: root.state = "GreenOn"
                        }
            
                        Button
                        {
                            id: btnOff
                            text: "Off"
                            onClicked: root.state = "RedOn"
                        }
            
                        Button
                        {
                            id: btnReset
                            text: "Reset"
                            onClicked: root.state = "BothOff"
                        }
            

            the next challenge would be to control the states from C++ side and choose specific items to edit.

            as I wrote above, I've checked on styleData.row and styleData.index but still can't figure out how to use them to my advantage, if you've got any other tip I would be grateful!

            1 Reply Last reply
            0
            • 6thC6 Offline
              6thC6 Offline
              6thC
              wrote on last edited by
              #6

              Oh hey. Cool, great to hear.

              I was using states and transitions mostly for GUI animations, as per my example below, I use transitions to animate the control color (in this case from State"inSpec" to "maximum" and "warning" to "maximum" states, I want an endless flashing red animation:

              Transition {
                        from: "inSpec"
                        to: "maximum"
                        SequentialAnimation {
                            loops: Animation.Infinite;
                            ColorAnimation { from: "transparent"; to: "red"; duration: 300 }
                            ColorAnimation { from: "red"; to: "transparent";  duration: 300 }
                        }
                    },
                    Transition {
                        from: "warning"
                        to: "maximum"
                        SequentialAnimation {
                            loops: Animation.Infinite;
                            ColorAnimation { from: "transparent"; to: "red";  duration: 300;        }
                            ColorAnimation { from: "red"; to: "transparent"; duration: 300;         }
                            }
                    }
              

              So I do control my data via c++ and the state of that data is how I control my GUI. The effect is c++ data is controlling the fronted but it's just the frontend reacting to the data inputs that happen to come from c++... I could have just as easily connected onto QML data etc.

              HaithamH 1 Reply Last reply
              0
              • 6thC6 6thC

                Oh hey. Cool, great to hear.

                I was using states and transitions mostly for GUI animations, as per my example below, I use transitions to animate the control color (in this case from State"inSpec" to "maximum" and "warning" to "maximum" states, I want an endless flashing red animation:

                Transition {
                          from: "inSpec"
                          to: "maximum"
                          SequentialAnimation {
                              loops: Animation.Infinite;
                              ColorAnimation { from: "transparent"; to: "red"; duration: 300 }
                              ColorAnimation { from: "red"; to: "transparent";  duration: 300 }
                          }
                      },
                      Transition {
                          from: "warning"
                          to: "maximum"
                          SequentialAnimation {
                              loops: Animation.Infinite;
                              ColorAnimation { from: "transparent"; to: "red";  duration: 300;        }
                              ColorAnimation { from: "red"; to: "transparent"; duration: 300;         }
                              }
                      }
                

                So I do control my data via c++ and the state of that data is how I control my GUI. The effect is c++ data is controlling the fronted but it's just the frontend reacting to the data inputs that happen to come from c++... I could have just as easily connected onto QML data etc.

                HaithamH Offline
                HaithamH Offline
                Haitham
                wrote on last edited by
                #7

                @6thC
                pretty nice

                Well as I am using static images (4 images only) I don't think I would need that in my application

                I would be so grateful if you would check my other post here

                I am trying to do something similar if I understood you correctly, I want the state of images to react to what happens in the back-end (C++ Obviously) but to do that I need to know how to address each item individually, so I thought QModelIndex holds the answer but I am stuck as shown in the post above.

                The big picture:

                I want to chage the state of the images of one item according to a condition met in the back-end (e.g. if the communication is established it would change the icon next to "Connected" from GreenOff to GreenOn) and so on for the rest of the code.

                Thanks a lot for your time, I owe you big time bro!

                1 Reply Last reply
                0
                • 6thC6 Offline
                  6thC6 Offline
                  6thC
                  wrote on last edited by
                  #8

                  No problems, I'm no expert but I think I can bail you out :-) - keep in mind this is just how I've solved this for myself. There are other resources for "QML States and Transitions" and "QML to C++" or "C++ to QML" around that are quite better than myself... saying that.

                  All you really need from there is to control the state based on some condition/expression.
                  So from there... a bit of scripting to set the object state either from within the control or externally doesn't really matter, but Connect is your friend.

                  I have my logic in another class for this example. My state is controlled via qml script:
                  example (QML):

                  function adjustState(control, incomingData){
                  ...
                    if( <incomingData evaluation for ok data>){
                                      // aok
                                      control.state =  "inSpec";
                                  }
                  ...
                    if( <incomingData evaluation for data entering close to max limit>){
                                      control.state =  "warning";
                  }
                  ...
                  
                    if( <incomingData evaluation for data value breached max limit>){
                                      control.state =  "maximum";
                  }
                  

                  Nothing hard to process - I do try to limit the processing work I throw to JavaScript engine but some is inevitable and this is pretty simple stuff for it and necessary.

                  My actual code there is a bit more complicated but I can probably only give you that as an example and hopefully you see it's setting a control's state property on some condition.

                  So then it's just connect the object to the c++ data.

                  I use C++ object instances. Lets pretend we have an C++ object that is referenced in the QML context such as: (c++)

                  context->setContextProperty(QStringLiteral("ObjectInstanceCpp"), &m_MyObject);
                  

                  now QML has that context, I can use m_MyObject from QML by using "ObjectInstanceCpp".

                  So let's take a peek at this c++ class ... I'll let you fill in the rest but this gives you a basic idea.

                  class SomethingSomethingName: public QObject
                  {
                      Q_OBJECT
                      Q_PROPERTY(int SimpleInt READ getSimpleIntProperty WRITE setSimpleIntProperty NOTIFY simpleIntPropertyChanged)
                  

                  in somewhere c++ we've declared SomethingSomethingName and it's now stored in m_MyObject, and as above I've made QML aware of this via setContextProperty.

                  From QML script I can then do things like:

                  Connections { target: ObjectInstanceCpp;
                  onSimpleIntPropertyChanged:{ adjustState(qmlControl, ObjectInstanceCpp.SimpleInt); }
                  

                  or even:

                  onSimpleIntPropertyChanged:{ 
                  var myLimit=20;
                  if(ObjectInstanceCpp.SimpleInt >myLimit ){
                  qmlControl.state = "maximum";
                  } 
                  }
                  

                  Hope this helps, this is not tested as I've had to cut a lot of my own application context out and rename things but hopefully helpful.

                  HaithamH 1 Reply Last reply
                  0
                  • 6thC6 6thC

                    No problems, I'm no expert but I think I can bail you out :-) - keep in mind this is just how I've solved this for myself. There are other resources for "QML States and Transitions" and "QML to C++" or "C++ to QML" around that are quite better than myself... saying that.

                    All you really need from there is to control the state based on some condition/expression.
                    So from there... a bit of scripting to set the object state either from within the control or externally doesn't really matter, but Connect is your friend.

                    I have my logic in another class for this example. My state is controlled via qml script:
                    example (QML):

                    function adjustState(control, incomingData){
                    ...
                      if( <incomingData evaluation for ok data>){
                                        // aok
                                        control.state =  "inSpec";
                                    }
                    ...
                      if( <incomingData evaluation for data entering close to max limit>){
                                        control.state =  "warning";
                    }
                    ...
                    
                      if( <incomingData evaluation for data value breached max limit>){
                                        control.state =  "maximum";
                    }
                    

                    Nothing hard to process - I do try to limit the processing work I throw to JavaScript engine but some is inevitable and this is pretty simple stuff for it and necessary.

                    My actual code there is a bit more complicated but I can probably only give you that as an example and hopefully you see it's setting a control's state property on some condition.

                    So then it's just connect the object to the c++ data.

                    I use C++ object instances. Lets pretend we have an C++ object that is referenced in the QML context such as: (c++)

                    context->setContextProperty(QStringLiteral("ObjectInstanceCpp"), &m_MyObject);
                    

                    now QML has that context, I can use m_MyObject from QML by using "ObjectInstanceCpp".

                    So let's take a peek at this c++ class ... I'll let you fill in the rest but this gives you a basic idea.

                    class SomethingSomethingName: public QObject
                    {
                        Q_OBJECT
                        Q_PROPERTY(int SimpleInt READ getSimpleIntProperty WRITE setSimpleIntProperty NOTIFY simpleIntPropertyChanged)
                    

                    in somewhere c++ we've declared SomethingSomethingName and it's now stored in m_MyObject, and as above I've made QML aware of this via setContextProperty.

                    From QML script I can then do things like:

                    Connections { target: ObjectInstanceCpp;
                    onSimpleIntPropertyChanged:{ adjustState(qmlControl, ObjectInstanceCpp.SimpleInt); }
                    

                    or even:

                    onSimpleIntPropertyChanged:{ 
                    var myLimit=20;
                    if(ObjectInstanceCpp.SimpleInt >myLimit ){
                    qmlControl.state = "maximum";
                    } 
                    }
                    

                    Hope this helps, this is not tested as I've had to cut a lot of my own application context out and rename things but hopefully helpful.

                    HaithamH Offline
                    HaithamH Offline
                    Haitham
                    wrote on last edited by
                    #9

                    @6thC did your application consist of a tree and you could apply a delegate to specific items? because that's where I'm stuck now. I am still researching on how to connect QML with C++ and as usual if I figured out a way of applying delegates to specific items based on a logical condition (like your warning and maximum states), I will let you know.

                    Thanks for your time bro!

                    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