Reputation: 2442
I have the following code:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
title: qsTr("Hello World!")
width: 640
height: 480
visible: true
menuBar: MenuBar {
id: menuBar
}
MouseArea
{
anchors.fill: parent
onClicked: { menuBar.menus.addItem("test") }
}
}
When I run it and click, the following message appears:
qrc:/main.qml:19: TypeError: Property 'addItem' of object [object Object] is not a function
Why is this?
EDIT: Getting the advice from https://stackoverflow.com/users/24283/timday I did this:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
title: qsTr("Hello World!")
width: 640
height: 480
visible: true
menuBar: MenuBar
{
id: menuBar
function addMenu(text)
{
var newObject = Qt.createQmlObject('import QtQuick.Controls 1.4; Menu { id: test; title: "Test" }',
menuBar, "dynamicSnippet1");
newObject.visible = true
}
}
MouseArea
{
anchors.fill: parent
onClicked: { menuBar.addMenu("Test") }
}
}
However, I cannot get the menu to show.
EDIT: Since it seems impossible to do what I want, I ended up with the recommendation of timday:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
title: qsTr("Hello World!")
width: 640
height: 480
visible: true
menuBar: MenuBar
{
id: menuBar
Menu { id: menu00; visible: false; }
Menu { id: menu01; visible: false; }
Menu { id: menu02; visible: false; }
Menu { id: menu03; visible: false; }
Menu { id: menu04; visible: false; }
Menu { id: menu05; visible: false; }
Menu { id: menu06; visible: false; }
Menu { id: menu07; visible: false; }
Menu { id: menu08; visible: false; }
Menu { id: menu09; visible: false; }
Menu { id: menu10; visible: false; }
Menu { id: menu11; visible: false; }
Menu { id: menu12; visible: false; }
Menu { id: menu13; visible: false; }
Menu { id: menu14; visible: false; }
Menu { id: menu15; visible: false; }
Menu { id: menu16; visible: false; }
Menu { id: menu17; visible: false; }
Menu { id: menu18; visible: false; }
Menu { id: menu19; visible: false; }
property variant topMenus: [ menu00, menu01, menu02, menu03, menu04,
menu05, menu06, menu07, menu08, menu09,
menu10, menu11, menu12, menu13, menu14,
menu15, menu16, menu17, menu18, menu19 ]
property int currMenu: 0
function addMenu(text)
{
if (currMenu == topMenus.length)
console.log("Index out of range")
else
{
var menu = topMenus[currMenu]
menu.visible = true
menu.title = text
currMenu++
return menu
}
}
}
MouseArea
{
anchors.fill: parent
onClicked: { menuBar.addMenu("Test") }
}
}
Upvotes: 2
Views: 2143
Reputation: 3
I found a solution for "showing" problem. Digging in MenuBarPrivate gave me an idea to use menusChanged() signal and it actually works.
Menu {
id: foo
...
}
MenuBar {
Component.onCompleted: {
menus.push(foo)
menusChanged()
}
}
Upvotes: 0
Reputation: 24892
You need to actually have a Menu
to your MenuBar
to add MenuItem
s to. Like this:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
title: qsTr("Hello World!")
width: 640
height: 480
visible: true
menuBar: MenuBar {
id: menuBar
Menu {
id: tests
title: "Tests"
}
}
MouseArea
{
anchors.fill: parent
onClicked: {
tests.addItem("Test");
}
}
}
This (run with Qt5.5.0's qmlscene) starts with a "Tests" Menu
in the bar, and adds a "Test" item to it every time you click (away from the menubar). You have to click to open the menu to see the items of course.
Dynamic creation of Menu
s is a little harder; see Qt.createQmlObject
or Qt.createComponent
docs. (It may be simpler to just declare all the ones you need in your code, but with their visible
property wired to whatever logic is appropriate).
Update: as you note in your updated question, and I've just confirmed myself, simply adding a dynamically created Menu
as a child of MenuBar
seems to be insufficient to get the Menu
to appear. I note it also doesn't result in the MenuBar
's menus
list getting any bigger. Unfortunately it's not easy to append to QML lists, they're different from JavaScript arrays. And there may be something funny about MenuBar... even attempting to assign a new list of menus, or an empty list, to it results in an error message. Might be worth raising an issue/request for better (or easier, if it is possible somehow) dynamic MenuBar
Menu
item in the QtJira... but I suspect any restrictions may arise from Qt's use of native menus on some platforms, forcing least-common-denominator levels of functionality maybe.
For a "Plan B" using initially hidden placeholders, this works sensibly on my Linux system:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4
ApplicationWindow {
title: qsTr("Hello World!")
width: 640
height: 480
visible: true
menuBar: MenuBar {
id: menubar
Menu {title: "File"}
Menu {id: testsmenu;title: "Tests";visible: false}
Menu {title: "Help"}
}
MouseArea {
anchors.fill: parent
onClicked: {
testsmenu.visible=true
testsmenu.addItem("Test")
}
}
}
More general point: it occurs to me I'm slightly suspicious of any application design which is predicated on having a very dynamic set of menu bar menus to show the user. Sort of the whole point of the menu UX pattern is that it's pretty static and users' "muscle memory" lets them navigate it fast... but if menus are fairly randomly coming and going that'll break. (OK some applications might present a different set of menus in a couple of different modes e.g IDEs with edit/debug modes, but that'd be quite doable with the "Plan B" style above and QML's notion of states and wiring menu visibility to application state).
Upvotes: 2