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. How to add Items dynamically to a Row? (in javascript)
Forum Update on Monday, May 27th 2025

How to add Items dynamically to a Row? (in javascript)

Scheduled Pinned Locked Moved Solved QML and Qt Quick
13 Posts 4 Posters 2.0k 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.
  • M Offline
    M Offline
    mbruel
    wrote on 21 Jul 2020, 17:49 last edited by mbruel
    #1

    Hi,
    I'm just learning QML and I'd like to factorize the creation of a Row using a js function.
    So basically in a js function create an Item using Qt.createComponent, affect all the properties and then add it to my Row.
    Is that possible?
    I'd expect sth like this

        Row {
            id: toolBar
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 20;
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 15
    
            height: 50
    
            function addItem(idName, imagePath){
                console.log("adding item: " + idName);
                var button = Qt.createComponent("ToolBarButton.qml");
                button.id = idName;
                button.imagePath = imagePath;
                button.height = toolBar.height;
                button.width = 50;
                button.state = "Inactive";
                button.barIndex = toolBar.children.length;
                toolBar.add(button);
            }
    
            Component.onCompleted: {
                addItem("home", "img/home.png");
            }
        }
    
    

    But I'm getting the error qrc:/main.qml:131: TypeError: Property 'add' of object QQuickRow_QML_2(0x56297448e670) is not a function

    O 1 Reply Last reply 21 Jul 2020, 18:15
    0
    • M mbruel
      21 Jul 2020, 17:49

      Hi,
      I'm just learning QML and I'd like to factorize the creation of a Row using a js function.
      So basically in a js function create an Item using Qt.createComponent, affect all the properties and then add it to my Row.
      Is that possible?
      I'd expect sth like this

          Row {
              id: toolBar
              anchors.bottom: parent.bottom
              anchors.bottomMargin: 20;
              anchors.horizontalCenter: parent.horizontalCenter
              spacing: 15
      
              height: 50
      
              function addItem(idName, imagePath){
                  console.log("adding item: " + idName);
                  var button = Qt.createComponent("ToolBarButton.qml");
                  button.id = idName;
                  button.imagePath = imagePath;
                  button.height = toolBar.height;
                  button.width = 50;
                  button.state = "Inactive";
                  button.barIndex = toolBar.children.length;
                  toolBar.add(button);
              }
      
              Component.onCompleted: {
                  addItem("home", "img/home.png");
              }
          }
      
      

      But I'm getting the error qrc:/main.qml:131: TypeError: Property 'add' of object QQuickRow_QML_2(0x56297448e670) is not a function

      O Offline
      O Offline
      ODБOï
      wrote on 21 Jul 2020, 18:15 last edited by
      #2

      hi

      @mbruel said in How to add Items dynamically to a Row? (in javascript):

      toolBar.add(button);

      @mbruel said in How to add Items dynamically to a Row? (in javascript):

      TypeError: Property 'add' of object QQuickRow_QML_2

      QML Row type has no add mathod

      see Dynamic QML Object Creation from JavaScript

      example

          Component.onCompleted: {
              createButton();
          }
      
          Row{
              id: row
              width: parent.width
              height: 50
          }
      
          function createButton() {
              var btn = btnComponent.createObject(row,{ text : "myButton"});
          }
      
          Component{
              id: btnComponent
              Button{}
          }
      
      1 Reply Last reply
      3
      • M Offline
        M Offline
        mbruel
        wrote on 21 Jul 2020, 18:51 last edited by
        #3

        hum I see, so I've updated my code to be:

                function addItem(idName, imagePath){
                    console.log("adding item: " + idName);
                    var c = Qt.createComponent("ToolBarButton.qml");
                    var button = c.createObject(toolBar, {
                                                            id: idName,
                                                            imagePath: imagePath,
                                                            height: toolBar.height,
                                                            width: 50,
                                                            state: "Inactive",
                                                            barIndex: toolBar.children.length
                                                        });
                }
        
                Component.onCompleted: {
                    addItem("profile", "img/profile.png");
                }
        
                Connections{
                    target: profile
                    onSelected: changeMainMenu(idx);
                }
        

        I'm getting now getting the issue: qrc:/main.qml:186: ReferenceError: profile is not defined

        So if I understand well I can't set the id of an object created dynamically? Is that right?
        This wouldn't be such a big deal but then how can I connect a signal of that object created dynamically?

        O 1 Reply Last reply 21 Jul 2020, 18:57
        0
        • M mbruel
          21 Jul 2020, 18:51

          hum I see, so I've updated my code to be:

                  function addItem(idName, imagePath){
                      console.log("adding item: " + idName);
                      var c = Qt.createComponent("ToolBarButton.qml");
                      var button = c.createObject(toolBar, {
                                                              id: idName,
                                                              imagePath: imagePath,
                                                              height: toolBar.height,
                                                              width: 50,
                                                              state: "Inactive",
                                                              barIndex: toolBar.children.length
                                                          });
                  }
          
                  Component.onCompleted: {
                      addItem("profile", "img/profile.png");
                  }
          
                  Connections{
                      target: profile
                      onSelected: changeMainMenu(idx);
                  }
          

          I'm getting now getting the issue: qrc:/main.qml:186: ReferenceError: profile is not defined

          So if I understand well I can't set the id of an object created dynamically? Is that right?
          This wouldn't be such a big deal but then how can I connect a signal of that object created dynamically?

          O Offline
          O Offline
          ODБOï
          wrote on 21 Jul 2020, 18:57 last edited by
          #4

          @mbruel

          function createButton() {
                 var btn = btnComponent.createObject(row,{ text : "myButton"});
                 btn.onClicked.connect(btnClicked)
             }
          
             function btnClicked(){console.log("button clicked")}
          
          1 Reply Last reply
          1
          • M Offline
            M Offline
            mbruel
            wrote on 21 Jul 2020, 19:09 last edited by
            #5

            great, I got what I wanted with that piece of code:

                Row {
                    id: toolBar
                    anchors.bottom: parent.bottom
                    anchors.bottomMargin: 20;
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: 15
            
                    height: 50
            
            
                    function addItem(idName){
                        console.log("adding item: " + idName);
                        var c = Qt.createComponent("ToolBarButton.qml");
                        var barIdx = toolBar.children.length;
                        var button = c.createObject(toolBar, {
                                                                id: idName,
                                                                imagePath: "img/"+idName+".png",
                                                                height: toolBar.height,
                                                                width: 50,
                                                                state: barIdx === 0 ? "Selected": "Inactive",
                                                                barIndex: toolBar.children.length
                                                            });
                        button.onSelected.connect(changeMainMenu);
                    }
            
            
                    Component.onCompleted: {
                        addItem("home");
                        addItem("mail");
                        addItem("compas");
                        addItem("stack");
                        addItem("profile");
                    }
                }
            

            my ToolBarButton Item is emitting the "selected" signal.

            Last question that is a bit out of the scope of this thread. How can I create a List of string that I would iterate in my onCompleted method?
            Like a property or simple variable of my root Window.

            O 1 Reply Last reply 21 Jul 2020, 19:13
            0
            • M mbruel
              21 Jul 2020, 19:09

              great, I got what I wanted with that piece of code:

                  Row {
                      id: toolBar
                      anchors.bottom: parent.bottom
                      anchors.bottomMargin: 20;
                      anchors.horizontalCenter: parent.horizontalCenter
                      spacing: 15
              
                      height: 50
              
              
                      function addItem(idName){
                          console.log("adding item: " + idName);
                          var c = Qt.createComponent("ToolBarButton.qml");
                          var barIdx = toolBar.children.length;
                          var button = c.createObject(toolBar, {
                                                                  id: idName,
                                                                  imagePath: "img/"+idName+".png",
                                                                  height: toolBar.height,
                                                                  width: 50,
                                                                  state: barIdx === 0 ? "Selected": "Inactive",
                                                                  barIndex: toolBar.children.length
                                                              });
                          button.onSelected.connect(changeMainMenu);
                      }
              
              
                      Component.onCompleted: {
                          addItem("home");
                          addItem("mail");
                          addItem("compas");
                          addItem("stack");
                          addItem("profile");
                      }
                  }
              

              my ToolBarButton Item is emitting the "selected" signal.

              Last question that is a bit out of the scope of this thread. How can I create a List of string that I would iterate in my onCompleted method?
              Like a property or simple variable of my root Window.

              O Offline
              O Offline
              ODБOï
              wrote on 21 Jul 2020, 19:13 last edited by ODБOï
              #6

              @mbruel said in How to add Items dynamically to a Row? (in javascript):

              Last question that is a bit out of the scope of this thread. How can I create a List of string that I would iterate in my onCompleted method?

              Like a property or simple variable of my root Window.

              https://doc.qt.io/qt-5/qtqml-syntax-objectattributes.html

              property var someList: [ "three", "four"]
              
              1 Reply Last reply
              0
              • M Offline
                M Offline
                mbruel
                wrote on 21 Jul 2020, 19:20 last edited by
                #7

                great, @LeLev you rock!

                here is the updated code:

                    Row {
                        property var menuList : ["home", "mail", "compas", "stack", "profile"]
                        
                        id: toolBar
                        anchors.bottom: parent.bottom
                        anchors.bottomMargin: 20;
                        anchors.horizontalCenter: parent.horizontalCenter
                        spacing: 15
                
                        height: 50
                
                
                        function addItem(idName){
                            console.log("adding item: " + idName);
                            var c = Qt.createComponent("ToolBarButton.qml");
                            var barIdx = toolBar.children.length;
                            var button = c.createObject(toolBar, {
                                                                    id: idName,
                                                                    imagePath: "img/"+idName+".png",
                                                                    height: toolBar.height,
                                                                    width: 50,
                                                                    state: barIdx === 0 ? "Selected": "Inactive",
                                                                    barIndex: toolBar.children.length
                                                                });
                            button.onSelected.connect(changeMainMenu);
                        }
                
                        Component.onCompleted: {
                            for (var i=0; i < menuList.length; ++i)
                                addItem(menuList[i]);
                        }
                    }
                
                1 Reply Last reply
                0
                • fcarneyF Offline
                  fcarneyF Offline
                  fcarney
                  wrote on 21 Jul 2020, 19:22 last edited by
                  #8

                  Here is another way to add unique items using a repeater and a loader (see last post):
                  https://forum.qt.io/topic/117076/random-customs-controls-in-a-row/3

                  C++ is a perfectly valid school of magic.

                  M 1 Reply Last reply 21 Jul 2020, 19:42
                  1
                  • fcarneyF fcarney
                    21 Jul 2020, 19:22

                    Here is another way to add unique items using a repeater and a loader (see last post):
                    https://forum.qt.io/topic/117076/random-customs-controls-in-a-row/3

                    M Offline
                    M Offline
                    mbruel
                    wrote on 21 Jul 2020, 19:42 last edited by
                    #9

                    @fcarney
                    sounds less intuitive but I'll have a look, thanks ;)

                    1 Reply Last reply
                    0
                    • GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on 22 Jul 2020, 07:47 last edited by
                      #10

                      You should refrain from using Qt.createComponent and manual dynamic instantiation in QML.

                      Stay declarative.

                      Your task can be achieved like so :

                      Row {
                         id: toolBar
                         property var menuList : ["home", "mail", "compas", "stack", "profile"]
                         property int currentIndex: 0
                          
                          anchors {
                              bottom: parent.bottom
                              bottomMargin: 20;
                              horizontalCenter: parent.horizontalCenter
                          }
                          spacing: 15
                          height: 50
                      
                          Repeater {
                              model: toolBar.menuList
                              ToolBarButton {
                                  id: button
                                  imagePath: "img/" + model.modelData + ".png"
                                  height: toolBar.height
                                  width: 50
                                  barIndex: model.index
                                  state:barIndex === toolBar.currentIndex ?  "Selected" : "Inactive"
                                  onSelected: toolBar.currentIndex = barIndex
                              }
                          }
                      }
                      

                      I also changed the selected button logic here to be self contained and because I didn't know what were the definition of your selected signal or changeMainMenu function.

                      M 1 Reply Last reply 22 Jul 2020, 08:43
                      2
                      • GrecKoG GrecKo
                        22 Jul 2020, 07:47

                        You should refrain from using Qt.createComponent and manual dynamic instantiation in QML.

                        Stay declarative.

                        Your task can be achieved like so :

                        Row {
                           id: toolBar
                           property var menuList : ["home", "mail", "compas", "stack", "profile"]
                           property int currentIndex: 0
                            
                            anchors {
                                bottom: parent.bottom
                                bottomMargin: 20;
                                horizontalCenter: parent.horizontalCenter
                            }
                            spacing: 15
                            height: 50
                        
                            Repeater {
                                model: toolBar.menuList
                                ToolBarButton {
                                    id: button
                                    imagePath: "img/" + model.modelData + ".png"
                                    height: toolBar.height
                                    width: 50
                                    barIndex: model.index
                                    state:barIndex === toolBar.currentIndex ?  "Selected" : "Inactive"
                                    onSelected: toolBar.currentIndex = barIndex
                                }
                            }
                        }
                        

                        I also changed the selected button logic here to be self contained and because I didn't know what were the definition of your selected signal or changeMainMenu function.

                        M Offline
                        M Offline
                        mbruel
                        wrote on 22 Jul 2020, 08:43 last edited by
                        #11

                        @GrecKo
                        Nice, thanks a lot!
                        Indeed it looks much better that way. I've checked the Repeater documentation and it's defo what I should use.
                        Here is the updated code which is nearly exactly what you gave me:

                            Row {
                                id: toolBar
                                anchors {
                                    bottom: parent.bottom
                                    bottomMargin: toolBarMargin;
                                    horizontalCenter: parent.horizontalCenter
                                }
                        
                                height:  toolBarHeight
                                spacing: toolBarSpacing
                        
                                Repeater {
                                    model: menuList
                                    ToolBarButton {
                                        id: button
                                        imagePath: "img/" + model.modelData + ".png"
                                        height: toolBar.height
                                        width: toolBarButtonWidth
                                        barIndex: model.index
                                        state: model.index === 0 ?  "Selected" : "Inactive"
                                        onSelected: changeMainMenu(barIndex);
                                    }
                                }
                        
                                Component.onCompleted: {
                                    toolBar.children[1].setBadge("3");
                                    toolBar.children[3].setBadge("12");
                                }
                            }
                        

                        The result is something like this:
                        alt text

                        My ToolBarButton have their opacity changing whether their state is Inactive, Hovered or Selected. When they emit the selected signal, the changeMainMenu function would change the state of the other buttons and the content of the main area (not sure yet how I'll achieve that, probably using a StackedView)

                            function changeMainMenu(selectedMenu){
                                console.log("New idx: "+selectedMenu)
                                for (var i = 0; i < toolBar.children.length; ++i)
                                {
                                    if (i !== selectedMenu)
                                        toolBar.children[i].state = "Inactive";
                                }
                            }
                        
                        GrecKoG 1 Reply Last reply 22 Jul 2020, 09:59
                        0
                        • M mbruel
                          22 Jul 2020, 08:43

                          @GrecKo
                          Nice, thanks a lot!
                          Indeed it looks much better that way. I've checked the Repeater documentation and it's defo what I should use.
                          Here is the updated code which is nearly exactly what you gave me:

                              Row {
                                  id: toolBar
                                  anchors {
                                      bottom: parent.bottom
                                      bottomMargin: toolBarMargin;
                                      horizontalCenter: parent.horizontalCenter
                                  }
                          
                                  height:  toolBarHeight
                                  spacing: toolBarSpacing
                          
                                  Repeater {
                                      model: menuList
                                      ToolBarButton {
                                          id: button
                                          imagePath: "img/" + model.modelData + ".png"
                                          height: toolBar.height
                                          width: toolBarButtonWidth
                                          barIndex: model.index
                                          state: model.index === 0 ?  "Selected" : "Inactive"
                                          onSelected: changeMainMenu(barIndex);
                                      }
                                  }
                          
                                  Component.onCompleted: {
                                      toolBar.children[1].setBadge("3");
                                      toolBar.children[3].setBadge("12");
                                  }
                              }
                          

                          The result is something like this:
                          alt text

                          My ToolBarButton have their opacity changing whether their state is Inactive, Hovered or Selected. When they emit the selected signal, the changeMainMenu function would change the state of the other buttons and the content of the main area (not sure yet how I'll achieve that, probably using a StackedView)

                              function changeMainMenu(selectedMenu){
                                  console.log("New idx: "+selectedMenu)
                                  for (var i = 0; i < toolBar.children.length; ++i)
                                  {
                                      if (i !== selectedMenu)
                                          toolBar.children[i].state = "Inactive";
                                  }
                              }
                          
                          GrecKoG Offline
                          GrecKoG Offline
                          GrecKo
                          Qt Champions 2018
                          wrote on 22 Jul 2020, 09:59 last edited by GrecKo
                          #12

                          @mbruel said in How to add Items dynamically to a Row? (in javascript):

                          My ToolBarButton have their opacity changing whether their state is Inactive, Hovered or Selected. When they emit the selected signal, the changeMainMenu function would change the state of the other buttons and the content of the main area (not sure yet how I'll achieve that, probably using a StackedView)

                          That's still not very declarative :)
                          Act on your data, not your visual items.
                          Items should follow the data.

                          I believe my proposed solution is better, maybe relocate the currentIndex property if you want.

                          Your solution:

                                     // in your main or elsewhere:
                                     function changeMainMenu(selectedMenu) {
                                          for (var i = 0; i < toolBar.children.length; ++i) {
                                                if (i !== selectedMenu)    
                                                    toolBar.children[i].state = "Inactive";
                                          }
                                      }
                                     // in your button
                                      state: model.index === 0 ?  "Selected" : "Inactive"
                                      onSelected: changeMainMenu(barIndex);
                          

                          You manipulate the properties of your items imperatively, you define in the state binding of the button (not really an actual binding since it will be overwritten by the changeMainMenu function anyway) that the first button is selected

                          My solution:

                                      // in the toolbar or elsewhere:
                                      property int selectedIndex: 0 // 0 is the initial selectedIndex
                                      // in your buttons
                                      state: barIndex === toolBar.selectedIndex ?  "Selected" : "Inactive"    
                                      onClicked: toolBar.selectedIndex = barIndex
                                      // ^ note that I changed it to a clicked signal, the button just tells how the user interacted with it
                                      //   it doesn't set itself as selected, the state binding does that.
                                      //   both your parent code and the button code becomes simpler
                          

                          @mbruel said in How to add Items dynamically to a Row? (in javascript):

                              Component.onCompleted: {
                                  toolBar.children[1].setBadge("3");
                                  toolBar.children[3].setBadge("12");
                              }
                          

                          Put that information in your model instead:

                          Repeater {
                              model: ListModel { // an array of JS objects would work here too
                                  ListElement { image: "home"; badge: 0 }
                                  ListElement { image: "mail"; badge: 3 }
                                  ListElement { image: "compas"; badge: 0 }
                                  ListElement { image: "stack"; badge: 12 }
                                  ListElement { image: "profile"; badge: 0 } 
                              }
                              ToolBarButton {
                                  ...
                                  imagePath: "img/" + model.image+ ".png"
                                  badge: model.badge
                              }
                          }
                          

                          Sorry if I'm being a purist, I just want to share my vision of how one should write QML ;)

                          I should also mention that I'm not a fan of the state property, but that's more opinion based.
                          In your case I would add a property bool selected property. Bind like so in the repeater: selected: model.index === selectedIndex
                          and in the button itself do: opacity: selected ? 1 : (hovered ? 0.7 : 0.4)

                          1 Reply Last reply
                          1
                          • M Offline
                            M Offline
                            mbruel
                            wrote on 22 Jul 2020, 11:13 last edited by mbruel
                            #13

                            @GrecKo said in How to add Items dynamically to a Row? (in javascript):

                                    state: barIndex === toolBar.selectedIndex ?  "Selected" : "Inactive"    
                                    onClicked: toolBar.selectedIndex = barIndex
                            

                            Hum I don't catch something.... The "state binding" doesn't seem to work correctly.
                            When I click on a button, so the selectedIndex "main variable" is set to the index of my button but then the state of the other buttons is not updated due to the change of the value of selectedIndex.
                            What in your solution would trigger that? (What my changeMainMenu is actually doing)

                            Put that information in your model instead

                            Cool will do, it sounds better but for now it is just a mock, I would get this info from C++. Hum, still for the initialization I could use that ListModel. I didn't read the QML model view framework yet...

                            Sorry if I'm being a purist, I just want to share my vision of how one should write QML ;)

                            don't be sorry, that's exactly what I'm looking for, get the best practices asap. Thanks for helping ;)

                            I should also mention that I'm not a fan of the state property, but that's more opinion based.

                            well I'm not a big fan either of states but I saw that in an example and it seems the easiest way to use Transitions.

                            // an array of JS objects would work here too

                            how you do that?

                            Otherwise for the mainArea I used a Loader that is reloaded in my changeMainMenu function. How would this work with your solution?

                            Here is my full main.qml:

                            import QtQuick 2.12
                            import QtQuick.Window 2.12
                            
                            Window {
                                id: root
                            
                                visible: true
                                width: 400
                                height: 600
                                title: qsTr("my QML app!")
                            
                                property int toolBarIndex       : 0
                                property int toolBarHeight      : 50;
                                property int toolBarSpacing     : 15;
                                property int toolBarMargin      : 20;
                                property int toolBarButtonWidth : 50;
                            
                                property int headerButtonSize   : 30;
                                property int mainMargin         : 20;
                            
                            //    property var menuList : ["home", "mail", "compas", "stack", "profile"]
                                ListModel {
                                    id: toolBarModel
                            
                                    ListElement { name : "home"    ; badge: "0"  ; color: "lightgreen" }
                                    ListElement { name : "mail"    ; badge: "3"  ; color: "lightblue" }
                                    ListElement { name : "compas"  ; badge: "0"  ; color: "lightgray" }
                                    ListElement { name : "stack"   ; badge: "12" ; color: "lightyellow" }
                                    ListElement { name : "profile" ; badge: "0"  ; color: "ivory" }
                                }
                            
                                Rectangle {
                                    id: background
                                    anchors {
                                        fill: parent;
                                        margins: 0;
                                    }
                                    color: "green"
                                    Image {
                                        source: "img/bg.png";
                                        fillMode: Image.Stretch;
                                        anchors.fill: parent;
                                        opacity: 1
                                    }
                                }
                            
                            
                                Loader {
                                    id: mainArea
                                    anchors {
                                        top: parent.top
                                        left: parent.left
                                        topMargin: mainMargin + headerButtonSize / 2;
                                        bottomMargin: mainMargin
                                        leftMargin: mainMargin
                                        rightMargin: mainMargin
                                    }
                                    width: parent.width - 2*mainMargin
                                    height: parent.height - 2*mainMargin - toolBarHeight - toolBarMargin
                                }
                            
                                ToolBarButton
                                {
                                    id: search
                                    anchors {
                                        top: parent.top
                                        left: parent.left
                                        margins: mainMargin;
                                    }
                                    width : headerButtonSize
                                    height: headerButtonSize
                            
                                    imagePath : "img/search.png"
                                    state     : "Inactive"
                                    selectable: false
                                }
                            
                                ToolBarButton
                                {
                                    id: chat
                                    anchors {
                                        top: parent.top
                                        right: parent.right
                                        margins: mainMargin;
                                    }
                                    width : headerButtonSize
                                    height: headerButtonSize
                            
                                    imagePath : "img/chat.png"
                                    state     : "Inactive"
                                    selectable: false
                                }
                            
                                Text {
                                    text: title
                                    anchors {
                                        top: parent.top
                                        horizontalCenter: parent.horizontalCenter
                                        topMargin: mainMargin;
                                    }
                                    color: "#ff0000"
                                    font.pointSize: 24
                                    font.bold: true
                                }
                            
                                function changeMainMenu(selectedMenu){
                                    console.log("New idx: "+selectedMenu)
                                    for (var i = 0; i < toolBar.children.length; ++i)
                                    {
                                        if (i !== selectedMenu)
                                            toolBar.children[i].state = "Inactive";
                                    }
                            
                                    mainArea.setSource("SimpleMainArea.qml");
                                    mainArea.item.lbl.text = toolBarModel.get(selectedMenu).name;//menuList[selectedMenu];
                                    mainArea.item.color    = toolBarModel.get(selectedMenu).color;
                                }
                            
                            
                                Row {
                                    id: toolBar
                                    anchors {
                                        bottom: parent.bottom
                                        bottomMargin: toolBarMargin;
                                        horizontalCenter: parent.horizontalCenter
                                    }
                            
                                    height : toolBarHeight
                                    spacing: toolBarSpacing
                            
                                    Repeater {
                                        model: toolBarModel; //menuList
                                        ToolBarButton {
                                            id: button
                                            height: toolBar.height
                                            width: toolBarButtonWidth
                            
                            //                imagePath: "img/" + model.modelData + ".png"
                                            imagePath: "img/" + model.name + ".png"
                                            barIndex: model.index
                            //                state: root.toolBarIndex === barIndex ? "Selected" : "Inactive"
                            //                onSelected: root.toolBarIndex = barIndex
                                            state: barIndex === root.toolBarIndex ?  "Selected" : "Inactive"
                                            onSelected: changeMainMenu(barIndex)
                                        }
                                    }
                            
                                    Component.onCompleted: {
                                        for (var i = 0; i < toolBar.children.length; ++i)
                                            toolBar.children[i].setBadge(toolBarModel.get(i).badge);
                                    }
                                }
                            
                                Component.onCompleted: {
                                    changeMainMenu(0);
                                }
                            
                            }
                            
                            

                            The SimpleMainArea.qml

                            import QtQuick 2.0
                            import QtQuick.Controls 2.14
                            
                            Rectangle {
                                property alias lbl: lbl
                            
                                radius: 10
                                opacity: 0.8
                            
                                Text  {
                                    id: lbl
                                    anchors {
                                        horizontalCenter: parent.horizontalCenter
                                        verticalCenter: parent.verticalCenter;
                                    }
                                    text: "not set...";
                                }
                            }
                            

                            and my ToolBarButton.qml so you can tell me if you see bad practices ;)

                            import QtQuick 2.12
                            import QtQuick.Controls 2.14
                            
                            Item {
                                id: button
                            
                                property string imagePath;
                                property int    barIndex   : 0;
                                property bool   selectable : true;
                            
                                property color color: "transparent"
                            
                                property double opacityInactive: 0.2
                                property double opacityHover   : 0.4
                                property double opacitySelected: 1
                            
                                property int borderWidth : 0
                                property int borderRadius: 0
                            
                            
                                property string previousState: "Inactive";
                            
                                property color badgeColor : "#ec3e3a";  // redish color (exactly the one used in OS X 10.10)
                            
                            
                            
                                // Allow the programmer to define the text to display.
                                // Note that this control can display both text and numbers.
                            //    property alias badgeText: badgeLbl.text
                            
                            
                                signal selected(int idx);
                            
                            
                            
                                //RectangItemle to draw the button
                                Rectangle {
                                    id: rect
                            
                                    anchors.fill: parent
                                    radius: borderRadius
                                    color: button.enabled ? button.color : "grey"
                            
                                    border.width: borderWidth
                                    border.color: "black"
                            
                                    opacity: opacityInactive
                            
                                    Image {
                                        id: img
                                        anchors.fill: parent;
                                        source: imagePath;
                                        fillMode: Image.PreserveAspectFit;
                                    }
                                }
                            
                                Rectangle {
                                    id: badge
                            
                                    visible: false
                                    smooth: true
                            
                                    // Create an animation when the opacity changes
                                    Behavior on opacity {NumberAnimation{}}
                            
                                    // Setup the anchors so that the badge appears on the bottom right
                                    // area of its parent
                                    anchors.right: rect.right
                                    anchors.top: rect.top
                            
                                    // This margin allows us to be "a little outside" of the object in which
                                    // we add the badge
                            //        anchors.margins: -parent.width / 5 + device.ratio(1)
                            
                                    color: badgeColor
                            
                                    // Make the rectangle a circle
                                    radius: width / 2
                            
                                    // Setup height of the rectangle (the default is 18 pixels)
                                    height: 18
                            
                                    // Make the rectangle and ellipse if the length of the text is bigger than 2 characters
                                    width: badgeLbl.text.length > 2 ? badgeLbl.paintedWidth + height / 2 : height
                            
                                    // Create a label that will display the number of connected users.
                                    Label {
                                        id: badgeLbl
                                        color: "#fdfdfdfd"
                                        font.pixelSize: 9
                                        anchors.fill: parent
                                        verticalAlignment: Text.AlignVCenter
                                        horizontalAlignment: Text.AlignHCenter
                            
                                        // We need to have the same margins as the badge so that the text
                                        // appears perfectly centered inside its parent.
                                        anchors.margins: parent.anchors.margins
                                    }
                                }
                            
                            
                                //Mouse area to react on click events
                                MouseArea {
                                    hoverEnabled: true
                                    anchors.fill: button
                                    onEntered: {
                                        button.previousState = button.state;
                                        if (button.state != 'Selected')
                                            button.state='Hover';
                            
                                    }
                            
                                    onExited : { button.state = previousState; }
                            
                                    onClicked: {
                                        if (selectable)
                                        {
                                            button.previousState = 'Selected';
                                            button.state         = 'Selected';
                                        }
                                        button.selected(button.barIndex);
                                    }
                                }
                            
                            
                                function setBadge(msg)
                                {
                                    if (msg !== "" && msg !== "0")
                                    {
                                        badge.visible = true;
                                        badgeLbl.text = msg;
                            
                                        badge.width = badgeLbl.text.length > 2 ? badgeLbl.paintedWidth + badgeLbl.height / 2 : badgeLbl.height;
                                    }
                                    else
                                        badge.visible = false;
                            
                                }
                            
                                function clearBadge() {badge.visible = false;}
                            
                            
                                //change the color of the button in differen button states
                                states: [
                                    State {
                                        name: "Inactive"
                                        PropertyChanges {
                                            target : rect
                                            opacity: opacityInactive
                                        }
                                    },
                                    State {
                                        name: "Hover"
                                        PropertyChanges {
                                            target : rect
                                            opacity: opacityHover
                                        }
                                    },
                                    State {
                                        name: "Selected"
                                        PropertyChanges {
                                            target : rect
                                            opacity: opacitySelected
                                        }
                                    }
                                ]
                            
                                state: previousState;
                            
                            
                                //define transmission for the states
                                transitions: [
                                    Transition {
                                        from: ""; to: "Hover"
                                        OpacityAnimator { duration: 200 }
                                    },
                                    Transition {
                                        from: "*"; to: "Selected"
                                        OpacityAnimator { duration: 10 }
                                    }
                                ]
                            }
                            

                            Edit: here is a small video of the desired behaviour

                            Edit2: my commented

                            //                state: root.toolBarIndex === barIndex ? "Selected" : "Inactive"
                            //                onSelected: root.toolBarIndex = barIndex
                            

                            is not stable, it is working the first time but then it seems the change of root.toolBarIndex doesn't impact all the buttons.. Any idea why?

                            1 Reply Last reply
                            0

                            1/13

                            21 Jul 2020, 17:49

                            • Login

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