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 Expandable Menu with SubItems
Forum Updated to NodeBB v4.3 + New Features

QML Expandable Menu with SubItems

Scheduled Pinned Locked Moved Solved QML and Qt Quick
13 Posts 3 Posters 11.2k 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.
  • QMLNewbieQ Offline
    QMLNewbieQ Offline
    QMLNewbie
    wrote on last edited by
    #4

    @JordanHarris: Thanks - I had seen the Expanding Delegates example, but not the shape shifting one. The problem is not the expanding mechanism, but how to populate the subItems in those two examples. If they are not all from one ListModel, I don't know how to use them for navigating - as in, currentIndex onClicked goes to this page, the other one goes to that page etc.

    @medyakovvit : That's really great, thank you! It is indeed quite ugly, and I am hesitant about writing to a bool variable in a ListModel, but it does seem to work for now. I'm gonna play around with it for a little bit more.

    M 1 Reply Last reply
    0
    • QMLNewbieQ QMLNewbie

      @JordanHarris: Thanks - I had seen the Expanding Delegates example, but not the shape shifting one. The problem is not the expanding mechanism, but how to populate the subItems in those two examples. If they are not all from one ListModel, I don't know how to use them for navigating - as in, currentIndex onClicked goes to this page, the other one goes to that page etc.

      @medyakovvit : That's really great, thank you! It is indeed quite ugly, and I am hesitant about writing to a bool variable in a ListModel, but it does seem to work for now. I'm gonna play around with it for a little bit more.

      M Offline
      M Offline
      medyakovvit
      wrote on last edited by
      #5

      @QMLNewbie
      it would be easier, if we have some Item that wraps items of section. But it's look like we haven't.

      1 Reply Last reply
      0
      • J Offline
        J Offline
        JordanHarris
        wrote on last edited by JordanHarris
        #6

        I attempted this and it was much harder than I expected. The way I attempted it was to modify the gist mentioned in the OP by making the sub item delegate another ListView. The reason I don't want to use sections like you do is because I would want top level items to be selectable, like normal items. Then I would want to be able to expand the sub items by clicking, tapping, or pressing a key (maybe enter or space). Then when it's expended, I'd like the sub ListView to gain focus and have keyboard navigation. I haven't gotten the keyboard and focus done yet, but I could at least make it all look right. I'll keep working on it and post my solution of I can get it working.

        1 Reply Last reply
        0
        • QMLNewbieQ Offline
          QMLNewbieQ Offline
          QMLNewbie
          wrote on last edited by
          #7

          I've been playing around with @medyakovvit 's example some more, but I am running into one big problem: I need the section delegate's color to change when the section is collapsed. This works fine if you collapse a section by clicking on it's own header. If you click on another section - which opens that section and collapses everything else - the other section delegates do not change color. I can not find any way of accessing them at all. The "section" property is just a string.

          I'm starting to think that this is simply not possible to do this!

          import QtQuick 2.6
          
          Item{
              id: root
              width: 1406; height: 536
              
              ListModel {
                  id: animalsModel
                  ListElement { name: "Puss in Boots"; type: "Cats"; aVisible: false}
                  ListElement { name: "Bengal"; type: "Cats"; aVisible: false }
                  ListElement { name: "Pug"; type: "Dogs"; aVisible: false }
                  ListElement { name: "German Shepherd"; type: "Dogs"; aVisible: false }
                  ListElement { name: "Parrot"; type: "Birds"; aVisible: false }
              }
              
              Component {
                  id: sectionHeader
                  
                  Rectangle {
                      id: testRect
                      width: 181
                      color:"green"
                      height: 50
                      
                      Text {
                          text: section
                          anchors.centerIn: parent
                      }
                      
                      MouseArea{
                          anchors.fill: parent
                          onClicked: {
                              console.log("clicked");
                              for(var i=0; i<animalsModel.count; i++)
                              {
                                  var animal = animalsModel.get(i);
                                  if(animal.type === section && animal.aVisible == false) {
                                      animal.aVisible = true;
                                      testRect.color = "red"
                                  }
                                  else if (animal.type === section && animal.aVisible == true) {
                                      animal.aVisible = false;
                                      testRect.color = "green"
                                  }
                                  
                                  else {
                                      animal.aVisible = false;
                                      //                            testRect.color = "green" //makes everything green
                                  }
                              }
                          }
                      }
                  }
              }
              
              
              ListView {
                  id: listing
                  width: 181
                  height: parent.height
                  model: animalsModel
                  
                  delegate: listdelegate
                  
                  section.property: "type"
                  section.criteria: ViewSection.FullString
                  section.delegate: sectionHeader
              }
              
              Component {
                  id: listdelegate
                  
                  Rectangle {
                      id: menuItem
                      width: 181
                      //height: 55
                      color: ListView.isCurrentItem ? "lightblue" : "white"
                      visible: aVisible
                      
                      onVisibleChanged: {
                          if(visible)
                              height = 55;
                          else
                              height = 0;
                      }
                      
                      Behavior on height {
                          NumberAnimation { duration: 300 }
                      }
                      
                      Text {
                          id: text
                          text: name
                          anchors.centerIn: parent
                      }
                      
                      MouseArea {
                          anchors.fill: parent
                          onClicked: {
                              listing.currentIndex = index;
                          }
                      }
                  }
              }
          }
          
          M 1 Reply Last reply
          0
          • QMLNewbieQ QMLNewbie

            I've been playing around with @medyakovvit 's example some more, but I am running into one big problem: I need the section delegate's color to change when the section is collapsed. This works fine if you collapse a section by clicking on it's own header. If you click on another section - which opens that section and collapses everything else - the other section delegates do not change color. I can not find any way of accessing them at all. The "section" property is just a string.

            I'm starting to think that this is simply not possible to do this!

            import QtQuick 2.6
            
            Item{
                id: root
                width: 1406; height: 536
                
                ListModel {
                    id: animalsModel
                    ListElement { name: "Puss in Boots"; type: "Cats"; aVisible: false}
                    ListElement { name: "Bengal"; type: "Cats"; aVisible: false }
                    ListElement { name: "Pug"; type: "Dogs"; aVisible: false }
                    ListElement { name: "German Shepherd"; type: "Dogs"; aVisible: false }
                    ListElement { name: "Parrot"; type: "Birds"; aVisible: false }
                }
                
                Component {
                    id: sectionHeader
                    
                    Rectangle {
                        id: testRect
                        width: 181
                        color:"green"
                        height: 50
                        
                        Text {
                            text: section
                            anchors.centerIn: parent
                        }
                        
                        MouseArea{
                            anchors.fill: parent
                            onClicked: {
                                console.log("clicked");
                                for(var i=0; i<animalsModel.count; i++)
                                {
                                    var animal = animalsModel.get(i);
                                    if(animal.type === section && animal.aVisible == false) {
                                        animal.aVisible = true;
                                        testRect.color = "red"
                                    }
                                    else if (animal.type === section && animal.aVisible == true) {
                                        animal.aVisible = false;
                                        testRect.color = "green"
                                    }
                                    
                                    else {
                                        animal.aVisible = false;
                                        //                            testRect.color = "green" //makes everything green
                                    }
                                }
                            }
                        }
                    }
                }
                
                
                ListView {
                    id: listing
                    width: 181
                    height: parent.height
                    model: animalsModel
                    
                    delegate: listdelegate
                    
                    section.property: "type"
                    section.criteria: ViewSection.FullString
                    section.delegate: sectionHeader
                }
                
                Component {
                    id: listdelegate
                    
                    Rectangle {
                        id: menuItem
                        width: 181
                        //height: 55
                        color: ListView.isCurrentItem ? "lightblue" : "white"
                        visible: aVisible
                        
                        onVisibleChanged: {
                            if(visible)
                                height = 55;
                            else
                                height = 0;
                        }
                        
                        Behavior on height {
                            NumberAnimation { duration: 300 }
                        }
                        
                        Text {
                            id: text
                            text: name
                            anchors.centerIn: parent
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                listing.currentIndex = index;
                            }
                        }
                    }
                }
            }
            
            M Offline
            M Offline
            medyakovvit
            wrote on last edited by
            #8

            @QMLNewbie
            Maybe this workaround is suits you:

            Item{
                    id: root
                    width: 1406; height: 536
            
                    ListModel {
                        id: animalsModel
                        ListElement { name: "Puss in Boots"; type: "Cats"; aVisible: false}
                        ListElement { name: "Bengal"; type: "Cats"; aVisible: false }
                        ListElement { name: "Pug"; type: "Dogs"; aVisible: false }
                        ListElement { name: "German Shepherd"; type: "Dogs"; aVisible: false }
                        ListElement { name: "Parrot"; type: "Birds"; aVisible: false }
                    }
            
                    Component {
                        id: sectionHeader          
            
                        Rectangle {
                            id: sectionHeaderRect
                            width: 181
                            color:"green"
                            height: 50
            
                            property var view: ListView.view
                            property var viewCurrentItem: ListView.view.currentItem
            
                            onViewCurrentItemChanged: {
                                if(viewCurrentItem){
                                    if(viewCurrentItem.section === section)
                                        color = "blue";
                                    else
                                        color = "green";
                                }
                            }
            
                            Text {
                                id: sectionHeaderText
                                text: section
                                anchors.centerIn: parent
                            }
            
                            MouseArea{
                                anchors.fill: parent
                                onClicked: {
                                    var firstInSection = false;
                                    for(var i=0; i<animalsModel.count; i++)
                                    {
                                        var animal = animalsModel.get(i);
                                        if(animal.type === section)
                                        {
                                            animal.aVisible = true;
                                            if(!firstInSection)
                                            {
                                                firstInSection = true;
                                                sectionHeaderRect.view.currentIndex = i;
                                            }
                                        }
                                        else
                                            animal.aVisible = false;
                                    }
                                }
                            }
                        }
                    }
            
            
                    ListView {
                        id: listing
                        width: 181
                        height: parent.height
                        model: animalsModel
            
                        delegate: listdelegate
            
                        section.property: "type"
                        section.criteria: ViewSection.FullString
                        section.delegate: sectionHeader
                    }
            
                    Component {
                        id: listdelegate
            
                        Rectangle {
                            id: menuItem
                            width: 181
                            //height: 55
                            color: ListView.isCurrentItem ? "lightblue" : "white"
                            property var section: ListView.section
                            visible: aVisible
            
                            onVisibleChanged: {
                                if(visible)
                                    height = 55;
                                else
                                    height = 0;
                            }
            
                            Behavior on height {
                                NumberAnimation { duration: 1000 }
                            }
            
                            Text {
                                id: text
                                text: name
                                anchors.centerIn: parent
                            }
            
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    listing.currentIndex = index;
                                }
                            }
                        }
                    }
                }
            
            1 Reply Last reply
            0
            • QMLNewbieQ Offline
              QMLNewbieQ Offline
              QMLNewbie
              wrote on last edited by
              #9

              Thanks @medyakovvit - I've spent the morning playing with this, but unfortunately every time you click on a Section Header, the currentIndex of the list changes. Since I am using the currentIndex to navigate between pages, that means the pages jump around every time you open or collapse a section.

              M 1 Reply Last reply
              0
              • QMLNewbieQ QMLNewbie

                Thanks @medyakovvit - I've spent the morning playing with this, but unfortunately every time you click on a Section Header, the currentIndex of the list changes. Since I am using the currentIndex to navigate between pages, that means the pages jump around every time you open or collapse a section.

                M Offline
                M Offline
                medyakovvit
                wrote on last edited by
                #10

                @QMLNewbie
                Ok, can you describe the behavior of listview one more time?

                1. How many sections can be collapsed at the same time?
                2. Do you need to highlight current section?

                It's look like you need view that behaves like TreeView but with custom appearance?

                1 Reply Last reply
                0
                • QMLNewbieQ Offline
                  QMLNewbieQ Offline
                  QMLNewbie
                  wrote on last edited by
                  #11

                  @medyakovvit : Thanks so much for helping me out, really appreciated.

                  Only one section can be open at a time. All the other sections should be collapsed. If you click on another section header, that one should open and the current open one should close. However, the currentIndex is independent of that. The currentIndex only changes when you actually click on a subitem. One you click on a subitem, currentIndex and therefore the content page changes.

                  So you could have subitem2 in section 1 selected and the corresponding page is open. If you then click on section2, that section opens, but subitem2 from section1 and it's page stay selected until you click on a different item.

                  As soon as you click on a section header, I need that section header to be highlighted (you can see in the original graphic here: http://pasteboard.co/xPyl3oy.jpg that an open section has the arrow pointing upwards instead of downwards).

                  I'll have a look at TreeView to see if that one would work! =)

                  M 1 Reply Last reply
                  0
                  • QMLNewbieQ QMLNewbie

                    @medyakovvit : Thanks so much for helping me out, really appreciated.

                    Only one section can be open at a time. All the other sections should be collapsed. If you click on another section header, that one should open and the current open one should close. However, the currentIndex is independent of that. The currentIndex only changes when you actually click on a subitem. One you click on a subitem, currentIndex and therefore the content page changes.

                    So you could have subitem2 in section 1 selected and the corresponding page is open. If you then click on section2, that section opens, but subitem2 from section1 and it's page stay selected until you click on a different item.

                    As soon as you click on a section header, I need that section header to be highlighted (you can see in the original graphic here: http://pasteboard.co/xPyl3oy.jpg that an open section has the arrow pointing upwards instead of downwards).

                    I'll have a look at TreeView to see if that one would work! =)

                    M Offline
                    M Offline
                    medyakovvit
                    wrote on last edited by
                    #12

                    @QMLNewbie

                    One more try:)

                    Item{
                            id: root
                            width: 1406; height: 536
                    
                            ListModel {
                                id: animalsModel
                                ListElement { name: "Puss in Boots"; type: "Cats"; aVisible: false}
                                ListElement { name: "Bengal"; type: "Cats"; aVisible: false }
                                ListElement { name: "Pug"; type: "Dogs"; aVisible: false }
                                ListElement { name: "German Shepherd"; type: "Dogs"; aVisible: false }
                                ListElement { name: "Parrot"; type: "Birds"; aVisible: false }
                            }
                    
                            Component {
                                id: sectionHeader
                    
                                Rectangle {
                                    id: sectionHeaderRect
                                    width: 181
                                    color:"green"
                                    height: 50
                    
                                    property bool isExpanded: false
                                    property string currentExpandedSection: ListView.view.expandedSection
                    
                                    onCurrentExpandedSectionChanged: {
                                        if(currentExpandedSection === section)
                                            isExpanded = true;
                                        else
                                            isExpanded = false;
                                    }
                    
                                    onIsExpandedChanged: {
                                        if(isExpanded){
                                            color = "blue";
                                            ListView.view.expandedSection = section;
                                        }
                                        else
                                            color = "green";
                                        for(var i=0; i<animalsModel.count; i++){
                                            var animal = animalsModel.get(i);
                                            if(section === animal.type)
                                                animal.aVisible = sectionHeaderRect.isExpanded;
                                        }
                                    }
                    
                                    Text {
                                        id: sectionHeaderText
                                        text: section
                                        anchors.centerIn: parent
                                    }
                    
                                    MouseArea{
                                        anchors.fill: parent
                                        onClicked: {
                                            sectionHeaderRect.isExpanded = !sectionHeaderRect.isExpanded;
                                        }
                                    }
                                }
                            }
                    
                    
                            ListView {
                                id: listing
                                width: 181
                                height: parent.height
                                model: animalsModel
                    
                                property string expandedSection: ""
                    
                                delegate: listdelegate
                    
                                section.property: "type"
                                section.criteria: ViewSection.FullString
                                section.delegate: sectionHeader
                    
                            }
                    
                            Component {
                                id: listdelegate
                    
                                Rectangle {
                                    id: menuItem
                                    width: 181
                                    //height: 55
                                    color: ListView.isCurrentItem ? "lightblue" : "white"
                                    visible: aVisible
                    
                                    onVisibleChanged: {
                                        if(visible)
                                            height = 55;
                                        else
                                            height = 0;
                                    }
                    
                                    Behavior on height {
                                        NumberAnimation { duration: 1000 }
                                    }
                    
                                    Text {
                                        id: text
                                        text: name
                                        anchors.centerIn: parent
                                    }
                    
                                    MouseArea {
                                        anchors.fill: parent
                                        onClicked: {
                                            listing.currentIndex = index;
                                        }
                                    }
                                }
                            }
                        }
                    
                    1 Reply Last reply
                    1
                    • QMLNewbieQ Offline
                      QMLNewbieQ Offline
                      QMLNewbie
                      wrote on last edited by
                      #13

                      @medyakovvit : EEEEK that's it!! Thank you so much! Took me a while to understand what you have done, but it works perfectly. Super thrilled that I can now move on to other things and don't have to worry about this one anymore, phew.

                      Thanks for helping a girl out! =)

                      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