[Solved] QML, how to make the contents of one menu dynamically depend on the contents of another
-
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.1ApplicationWindow {
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.0Rectangle {
// Android-style Action bar
property alias barHeight: actionBar.height
property list<Action> actions
property list<Action> moreActionsid: 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.1Item {
property Action action
property alias iconHeight: actionButton.height
property alias isEnabled: actionButton.enabledid: 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 }
}
@ -
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)
}
}
@