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. "Dynamically" add QML menu items based on C++?
Forum Updated to NodeBB v4.3 + New Features

"Dynamically" add QML menu items based on C++?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
12 Posts 4 Posters 2.1k Views 1 Watching
  • 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.
  • jeremy_kJ jeremy_k

    The documentation has a section on dynamic content, using Menu.addAction() or one of a set of similar functions.

    https://doc.qt.io/qt-6/qml-qtquick-controls-menu.html#dynamically-generating-menu-items

    Tom assoT Offline
    Tom assoT Offline
    Tom asso
    wrote on last edited by
    #3

    @jeremy_k - Awesome, thank you!

    Tom assoT 1 Reply Last reply
    0
    • Tom assoT Tom asso

      @jeremy_k - Awesome, thank you!

      Tom assoT Offline
      Tom assoT Offline
      Tom asso
      wrote on last edited by Tom asso
      #4

      @jeremy_k Thanks- looking at the link you provided, but I cannot find any examples of how Menu.addAction() (and other methods) are actually used in QML code. Do you know of an example? In my case, menu item names are stored in string array cmaps, and my QML looks like:

      Menu {
         title: "TEST"
         id: testMenu
         Component.onCompleted: {
         // Insert menu items with names 
         // from cmaps array	
         for (var i = 0; i < cmaps.length; i++)  { 
            console.log("map: ", cmaps[i])
             testMenu.addItem({"text":cmaps[i]});
         } 
      }
      

      I can see the loop being executed, but items do not appear in the menu - do you know what I am missing? Thanks!

      jeremy_kJ 1 Reply Last reply
      0
      • Tom assoT Offline
        Tom assoT Offline
        Tom asso
        wrote on last edited by Tom asso
        #5

        I solved this with the following implementation, using Qt.createQmlObject() to create an Action and add it to the menu with Menu.addAction():

        Menu {
          title: "TEST"
          id: testMenu
          // Create and add Actions to menu
          Component.onCompleted: {
            // Insert menu items here, with number of items 
            // and item names as specified in the cmaps[] array that was
            // retrieved from C++
            for (var i = 0; i < cmaps.length; i++)  {
              // Build QML string that specifies menu Action to add
              var qmlStr = 
                 "import QtQuick.Controls 2.3; Action {id: myAction; text: \"" + cmaps[i] + "\"}";
            // Create the menu Action
             var obj = 
                    Qt.createQmlObject(qmlStr,
                          testMenu,
                         "dynamicAction");
                              
             // Add created Action to the menu    
             testMenu.addAction(obj);
           }
        }
        

        Thanks to @jeremy_k for the suggestion!

        B 1 Reply Last reply
        0
        • Tom assoT Tom asso

          @jeremy_k Thanks- looking at the link you provided, but I cannot find any examples of how Menu.addAction() (and other methods) are actually used in QML code. Do you know of an example? In my case, menu item names are stored in string array cmaps, and my QML looks like:

          Menu {
             title: "TEST"
             id: testMenu
             Component.onCompleted: {
             // Insert menu items with names 
             // from cmaps array	
             for (var i = 0; i < cmaps.length; i++)  { 
                console.log("map: ", cmaps[i])
                 testMenu.addItem({"text":cmaps[i]});
             } 
          }
          

          I can see the loop being executed, but items do not appear in the menu - do you know what I am missing? Thanks!

          jeremy_kJ Offline
          jeremy_kJ Offline
          jeremy_k
          wrote on last edited by
          #6

          @Tom-asso said in "Dynamically" add QML menu items based on C++?:

          @jeremy_k Thanks- looking at the link you provided, but I cannot find any examples of how Menu.addAction() (and other methods) are actually used in QML code. Do you know of an example? In my case, menu item names are stored in string array cmaps, and my QML looks like:

          Menu {
             title: "TEST"
             id: testMenu
             Component.onCompleted: {
             // Insert menu items with names 
             // from cmaps array	
             for (var i = 0; i < cmaps.length; i++)  { 
                console.log("map: ", cmaps[i])
                 testMenu.addItem({"text":cmaps[i]});
             } 
          }
          

          I can see the loop being executed, but items do not appear in the menu - do you know what I am missing? Thanks!

          I see that you solved the problem in the following post. Perhaps you figured out the issue in the version above. If not:

          The reason it fails is that addItem() takes a Quick Item, but the code is passing a javascript dictionary object.

          Asking a question about code? http://eel.is/iso-c++/testcase/

          1 Reply Last reply
          1
          • Tom assoT Tom asso

            I solved this with the following implementation, using Qt.createQmlObject() to create an Action and add it to the menu with Menu.addAction():

            Menu {
              title: "TEST"
              id: testMenu
              // Create and add Actions to menu
              Component.onCompleted: {
                // Insert menu items here, with number of items 
                // and item names as specified in the cmaps[] array that was
                // retrieved from C++
                for (var i = 0; i < cmaps.length; i++)  {
                  // Build QML string that specifies menu Action to add
                  var qmlStr = 
                     "import QtQuick.Controls 2.3; Action {id: myAction; text: \"" + cmaps[i] + "\"}";
                // Create the menu Action
                 var obj = 
                        Qt.createQmlObject(qmlStr,
                              testMenu,
                             "dynamicAction");
                                  
                 // Add created Action to the menu    
                 testMenu.addAction(obj);
               }
            }
            

            Thanks to @jeremy_k for the suggestion!

            B Offline
            B Offline
            Bob64
            wrote on last edited by Bob64
            #7

            @Tom-asso I know you have already got a solution, but I wonder if the approach suggested in this link might work for you. The idea is to define your dynamic menu entries by means of a model, and instantiate the items using a repeater. In your case you could expose the model from C++.

            From the link:

            Menu {
                id:contextMenu
                visible: true
                Repeater {
                    model: menuItems
                    MenuItem {
                        text: modelData
                    }
                }
            }
            

            The example instantiates MenuItem though, rather than Action, and Repeater is documented as only working with Item-based elements, which Action isn't. I don't know if there is a way around this, but if there were some way to get it to work, it would be a more "QML" way of doing it.

            Tom assoT 1 Reply Last reply
            1
            • B Bob64

              @Tom-asso I know you have already got a solution, but I wonder if the approach suggested in this link might work for you. The idea is to define your dynamic menu entries by means of a model, and instantiate the items using a repeater. In your case you could expose the model from C++.

              From the link:

              Menu {
                  id:contextMenu
                  visible: true
                  Repeater {
                      model: menuItems
                      MenuItem {
                          text: modelData
                      }
                  }
              }
              

              The example instantiates MenuItem though, rather than Action, and Repeater is documented as only working with Item-based elements, which Action isn't. I don't know if there is a way around this, but if there were some way to get it to work, it would be a more "QML" way of doing it.

              Tom assoT Offline
              Tom assoT Offline
              Tom asso
              wrote on last edited by
              #8

              @Bob64 - Thanks. In my application, the qml doesn't "know" the list of menu item names, which is provided by C++. But the C++ does not change that name list while the application is running, so it seems a bit more complex to use model rather than just a string array of names.

              1 Reply Last reply
              0
              • jeremy_kJ Offline
                jeremy_kJ Offline
                jeremy_k
                wrote on last edited by
                #9

                @Tom-asso said in "Dynamically" add QML menu items based on C++?:

                @Bob64 - Thanks. In my application, the qml doesn't "know" the list of menu item names, which is provided by C++. But the C++ does not change that name list while the application is running, so it seems a bit more complex to use model rather than just a string array of names.

                A list is a valid model for Quick items that take a model.

                import QtQuick
                import QtQuick.Controls
                import QtQml.Models
                Window {
                    width: 100
                    height: 50
                    visible: true
                    Menu {
                        id: menu
                        Instantiator {
                            model: ["first", "second"]
                            delegate: MenuItem { text: modelData }
                            onObjectAdded: (index, object) => menu.insertItem(index, object)
                        }
                        Component.onCompleted: popup()
                    }
                }
                

                Asking a question about code? http://eel.is/iso-c++/testcase/

                GrecKoG 1 Reply Last reply
                2
                • jeremy_kJ jeremy_k

                  @Tom-asso said in "Dynamically" add QML menu items based on C++?:

                  @Bob64 - Thanks. In my application, the qml doesn't "know" the list of menu item names, which is provided by C++. But the C++ does not change that name list while the application is running, so it seems a bit more complex to use model rather than just a string array of names.

                  A list is a valid model for Quick items that take a model.

                  import QtQuick
                  import QtQuick.Controls
                  import QtQml.Models
                  Window {
                      width: 100
                      height: 50
                      visible: true
                      Menu {
                          id: menu
                          Instantiator {
                              model: ["first", "second"]
                              delegate: MenuItem { text: modelData }
                              onObjectAdded: (index, object) => menu.insertItem(index, object)
                          }
                          Component.onCompleted: popup()
                      }
                  }
                  
                  GrecKoG Offline
                  GrecKoG Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on last edited by GrecKo
                  #10

                  An Instantiator is not needed, Menu can handle dynamically added MenuItem by a Repeater.
                  Use the code provided by bob64.
                  And like jeremy_k said you don't have to pass it a full fledged QAbstractItemModel, a string list is fine.

                  jeremy_kJ 1 Reply Last reply
                  0
                  • GrecKoG GrecKo

                    An Instantiator is not needed, Menu can handle dynamically added MenuItem by a Repeater.
                    Use the code provided by bob64.
                    And like jeremy_k said you don't have to pass it a full fledged QAbstractItemModel, a string list is fine.

                    jeremy_kJ Offline
                    jeremy_kJ Offline
                    jeremy_k
                    wrote on last edited by
                    #11

                    @GrecKo said in "Dynamically" add QML menu items based on C++?:

                    An Instantiator is not needed, Menu can handle dynamically added MenuItem by a Repeater.

                    Except that as @Bob64 points out, Repeater cannot handle non-Item delegates. It will work for MenuItem, but not Menu or Action.

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    GrecKoG 1 Reply Last reply
                    0
                    • jeremy_kJ jeremy_k

                      @GrecKo said in "Dynamically" add QML menu items based on C++?:

                      An Instantiator is not needed, Menu can handle dynamically added MenuItem by a Repeater.

                      Except that as @Bob64 points out, Repeater cannot handle non-Item delegates. It will work for MenuItem, but not Menu or Action.

                      GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on last edited by
                      #12

                      @jeremy_k not working with Action is not really an issue since you are in charge of chosing the delegate type, so you can create a MenuItem instead (that's what the Menu does anyway when adding an Action).

                      Instantiator is indeed needed for nested Menus.

                      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