Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Discover and share your #QtStories


    Fill out our CSRD Survey


    [Solved] QML, how to make the contents of one menu dynamically depend on the contents of another

    QML and Qt Quick
    1
    2
    3008
    Loading More Posts
    • 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
      MartynW last edited by

      I am trying to understand how best to use QML by implementing my own Android action bar.
      The action bar has the traditional app icon and name, then some action buttons representing common actions, then an 'action overflow' button for further actions. When the action bar is narrow, there is less room for the action buttons and I want them to overflow to the secondary menu under the action overflow button.

      I have an action bar with 4 action buttons that can resize, so buttons that overlap with the app name are not showing, and I have a secondary menu that shows zero or all of the actions depending on an int property. My problem is how do I set that int dynamically depending on which action buttons are showing.

      If I set the visible property of the action buttons (so as to use visibleChildren.length of the action bar) then the QML seems to loop. If I don't use the visible property but instead set the icon source to an empty string, then how can I dynamically determine how many action buttons have an empty string?

      I would appreciate suggestions on what might be the recommended way to do this in QML.

      Thank you.

      main.qml:

      @import QtQuick 2.1
      import QtQuick.Controls 1.0
      import QtGraphicalEffects 1.0
      import QtQuick.Window 2.1

      ApplicationWindow {
      property real scaleFactor: Screen.pixelDensity / 5.0
      property int intScaleFactor: Math.max(1, scaleFactor)

      width: 640; height: 480
      
      property list<Action> actionsList: [
          Action { text: "Sightings"; iconSource: "qrc:/sightings"; onTriggered: image1.visible = !image1.visible },
          Action { text: "Alerts";    iconSource: "qrc:/alerts";    onTriggered: image1.visible = !image1.visible },
          Action { text: "Search";    iconSource: "qrc:/search";    onTriggered: image1.visible = !image1.visible }
      ]
      property list<Action> moreActionsList: [
          Action { text: "About"; onTriggered: image1.visible = !image1.visible }
      ]
      
      ActionBar {
          id: actionBar
          barHeight: slider.value
          actions: actionsList
          moreActions: moreActionsList
      }
      
      Image {
          id: image1 x: 270 y: 257
          width: 100 height: 100 source: "qrc:/drs"
      }
      Slider {
          id: slider
          anchors { topMargin: 150; top: parent.top; }
          minimumValue: 30 maximumValue : 150 value: 80
      }
      

      }
      @

      ActionBar.qml

      @import QtQuick 2.1
      import QtQuick.Controls 1.0
      import QtGraphicalEffects 1.0

      Rectangle {
      // Android-style Action bar
      property alias barHeight: actionBar.height
      property list<Action> actions
      property list<Action> moreActions

      id: actionBar
      height: 80
      anchors { right: parent.right; left: parent.left; top: parent.top; }
      Image {
          id: image2
          height: barHeight * 0.9; width: height
          anchors { leftMargin: 15; left: parent.left; verticalCenter: parent.verticalCenter; }
          source: "qrc:/drs"
      }
      Text {
          id: titletext
          text: "ApplicationName" color: "white" font.bold: true
          font.pixelSize: barHeight * 0.33
          anchors { leftMargin: barHeight / 5; left: image2.right; verticalCenter: parent.verticalCenter; }
      }
      property int actCount: 0
      Row {
          id: actionsRow
          anchors { right: parent.right; verticalCenter: parent.verticalCenter; }
          Repeater {
              id: repeat
              model: actions
              ActionBarActionDelegate {
                  // Does action icon overlap with the title text
                  property bool isNoOverlap: ((titletext.x + titletext.width) < (actionsRow.x + actionsRow.children[index].x))
                  iconHeight: barHeight * 0.9
                  action: Action {
                      // Have an enpty icon if it would overlap the title text
                      iconSource: isNoOverlap ? modelData.iconSource : ""
                      text: modelData.text
                      onTriggered: { modelData.triggered(); }
                  }
                  // Disable actions that would overlap the title text
                  isEnabled: isNoOverlap
              }
          }
          // Now the optional More options icon
          ActionBarActionDelegate {
              iconHeight: barHeight * 0.9
              action: Action { iconSource: "qrc:/more"; onTriggered: { console.log(actCount);
                      overflowMenu.popup() }
              }
          }
      }
      
      Rectangle {
          // Action bar shadow
          id: actionBarShadow
          height: barHeight > 60 ? 5 : 2
          width: parent.width color: "darkgray" anchors { top: parent.bottom; }
      }
      property int overflowCount: 1 //actionsRow.visibleChildren.length
      
      Menu {
          id: overflowMenu
          title: "Edit"
      
          Instantiator {
              id: inst
              model: actionsList
              MenuItem {
                  text: modelData.text
                  visible: (index < overflowCount)
                  onTriggered: modelData.triggered()
              }
              onObjectAdded: overflowMenu.insertItem(index, object)
              onObjectRemoved: overflowMenu.removeItem(object)
          }
      
          MenuSeparator { visible: (overflowCount > 0) }
      
          MenuItem { text: "About"
              onTriggered: console.log("overflowCount =", overflowCount); }
      }
      

      }
      @

      ActionBarActionDelegate.qml

      @import QtQuick 2.0
      import QtQuick.Controls 1.1

      Item {
      property Action action
      property alias iconHeight: actionButton.height
      property alias isEnabled: actionButton.enabled

      id: actionButton height: 70 width: height
      
      Image {
          id: iconImage
          anchors.fill: parent
          source: action ? action.iconSource : ""
      }
      Rectangle {
          // Hint to show when icon is clicked
          id: iconClickedArea
          anchors.fill: parent
          color: "darkgray" opacity: 0
      }
      MouseArea {
          anchors.fill: parent
          onClicked: action.triggered()
          onEntered: iconClickedArea.opacity = action ? 0.5 : 0
          onExited:  iconClickedArea.opacity = 0
      }
      

      }
      @

      1 Reply Last reply Reply Quote 0
      • M
        MartynW last edited by

        I think I may have finally worked out a way to do this. In the ActionBarActionDelegate I need to latch onto the enabled property and then effectively export this by emitting a signal for the ActionBar to handle. It can handle it by setting the int property to the appropriate action button count.

        in ActionBarActionDelegate:
        @Item {
        property int actionIndex: 0 // Index of the action in the action bar list (if set)
        property Action action
        property alias iconHeight: actionButton.height
        signal activationChanged(int actionIndex, bool active)

        id: actionButton
        height: 70
        width: height
        
        onEnabledChanged: activationChanged(actionIndex, enabled)
        

        ...@

        and in ActionBar
        @ ActionBarActionDelegate {
        iconHeight: barHeight * 0.9
        actionIndex: index
        action: Action {
        iconSource: modelData.iconSource
        text: modelData.text
        onTriggered: { modelData.triggered(); }
        }
        // Does action icon overlap with the title text?
        // Disable (and implicitly hide) actions that would overlap the title text
        enabled: ((titletext.x + titletext.width) < (actionsRow.x + actionsRow.children[index].x))
        onActivationChanged: {
        if (active && actionIndex < overflowCount)
        overflowCount = actionIndex
        else if (!active && actionIndex >= overflowCount)
        overflowCount = actionIndex + 1
        console.log("Activated on index:", actionIndex, "as", active, "overflowCount:", overflowCount)
        }
        }
        @

        1 Reply Last reply Reply Quote 0
        • First post
          Last post