Ошибка добавления меню в 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, теперь полностью работает (но с ошибкой). Спасибо БаКа.   -  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, чтобы добавить MenuItem к ним. Как это:

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 на панели и добавляет к нему элемент «Тест» каждый раз, когда вы щелкаете (вдали от строки меню). Вы должны щелкнуть, чтобы открыть меню, чтобы увидеть элементы, конечно.

Динамическое создание Menu немного сложнее; см. 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