Грешка при добавяне на меню в QML

Имам следния код:

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") }
    }
}

Когато го стартирам и щракна, се появява следното съобщение:

qrc:/main.qml:19: TypeError: Property 'addItem' of object [object Object] is not a function

Защо е това?

РЕДАКТИРАНЕ: Получавайки съвета от https://stackoverflow.com/users/24283/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

        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") }
    }
}

Не мога обаче да накарам менюто да се покаже.

РЕДАКТИРАНЕ: Тъй като изглежда невъзможно да направя това, което искам, завърших с препоръката на 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") }
    }
}

person chila    schedule 21.08.2015    source източник
comment
Моля, предоставете напълно работещ код без зависимости или неща, които могат да блокират изпълнението.   -  person BaCaRoZzo    schedule 22.08.2015
comment
а? Този е напълно работещ (до момента, в който щракнете) QML код; Qt5.5 qmlscene го изпълнява добре.   -  person timday    schedule 22.08.2015
comment
Модифицирах според BaCaRoZzo, сега работи напълно (но с грешката). Благодаря BaCa.   -  person chila    schedule 22.08.2015
comment
ААА разбирам; Трябваше да проверя хронологията на редакциите.   -  person timday    schedule 22.08.2015
comment
Хммм, аз се опитах да създам някакво динамично меню и също нямах много късмет; още няколко коментара в моя актуализиран отговор.   -  person timday    schedule 22.08.2015
comment
След последната актуализация: уау... колко менюта в лентата с менюта са твърде много менюта в лентата с менюта? :^)   -  person timday    schedule 25.08.2015


Отговори (2)


Всъщност трябва да имате Menu към вашия MenuBar, за да добавите MenuItems към него. Като този:

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");
    }
  }
}

Това (изпълнява се с qmlscene на Qt5.5.0) започва с „Тестове“ Menu в лентата и добавя елемент „Тест“ към него всеки път, когато щракнете (далеч от лентата с менюта). Трябва да щракнете, за да отворите менюто, за да видите елементите, разбира се.

Динамичното създаване на Menus е малко по-трудно; вижте Qt.createQmlObject или Qt.createComponent документи. (Може да е по-просто просто да декларирате всички тези, от които се нуждаете във вашия код, но с тяхното свойство visible, свързано с каквато и да е подходяща логика).

Актуализация: както отбелязвате в актуализирания си въпрос и току-що се потвърдих, простото добавяне на динамично създаден Menu като дете на MenuBar изглежда недостатъчно, за да се появи Menu. Отбелязвам, че това също не води до увеличаване на списъка с menus на MenuBar. За съжаление не е лесно да добавите към QML списъци, те са различни от JavaScript масиви. И може да има нещо смешно в MenuBar... дори опитът за присвояване на нов списък с менюта или празен списък към него води до съобщение за грешка. Може би си струва да повдигнете проблем/искане за по-добър (или по-лесен, ако е възможно по някакъв начин) динамичен MenuBar Menu елемент в QtJira... но подозирам, че могат да възникнат ограничения от използването на естествени менюта от Qt на някои платформи, принуждавайки най-малко- общи нива на функционалност може би.

За „План Б“, използващ първоначално скрити контейнери, това работи разумно на моята Linux система:

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")
    }
  }
}

По-обща точка: Струва ми се, че съм леко подозрителен към всеки дизайн на приложение, който се основава на наличието на много динамичен набор от менюта на лентата с менюта, които да се показват на потребителя. Един вид целта на UX модела на менюто е, че той е доста статичен и „мускулната памет“ на потребителите им позволява да го навигират бързо... но ако менютата се появяват и изчезват доста случайно, това ще се счупи. (ОК, някои приложения може да представят различен набор от менюта в няколко различни режима, напр. IDE с режими за редактиране/отстраняване на грешки, но това би било доста изпълнимо със стила „План Б“ по-горе и представата на QML за състояния и видимост на менюто за окабеляване състояние на приложението).

person timday    schedule 21.08.2015
comment
Това, което искам да направя, е динамично да създам менюто „тест“. Ще разгледам тези документи, благодаря. - person chila; 22.08.2015
comment
Направих модификация според вашия съвет. - person chila; 22.08.2015
comment
Приложението, което създавам, е далеч от обикновеното ;) Бъдете подозрителни. - person chila; 22.08.2015

Намерих решение за проблема с "показването". Ровенето в MenuBarPrivate ми даде идея да използвам сигнала menusChanged() и той наистина работи.

Menu {
   id: foo
   ...
}

MenuBar {
   Component.onCompleted: {
        menus.push(foo)
        menusChanged()
    }
}
person Max Bespalov    schedule 20.02.2020