Вопрос

Я создал модель, которая перечисляет существующие конфигурации (скажем, это перечислены «файлы», так как это не имеет значения здесь). Пока что работает хорошо, когда прикреплен к QListView.

Пример:

--- ListView ---
- file #1      -
- file #2      -
- file #3      -
- file #4      -
----------------

Можно ли использовать ту же модель для динамически обновления QMenu ?

Что-то типа:

Menu
-> Submenu #1
-> Submenu #2
-> File-submenu
  -> file #1
  -> file #2
  -> file #3
  -> file #4
-> Submenu #3

Короче говоря: есть ли способ создать список динамичных обновлений QActionS (сгруппирован в то же самое QMenu) в зависимости от модель (полученный из QAbstractListModel) ?

Это было полезно?

Решение

Если ваша цель - просто обновить свой меню, с помощью текста элемента, которые доступны в QAbstractListModel, Затем ответ да.

Вот путь ..

Индивидуальный индекс элемента может быть получен с помощью следующей функции.

QModelIndex QAbstractListModel::index ( int row, int column = 0, 
const QModelIndex & parent = QModelIndex() ) const   [virtual]

С полученным индексом данные могут быть получены,

 QVariant QModelIndex::data ( int role = Qt::DisplayRole ) const

Затем доступный текст в индексе может быть получен с использованием,

QString QVariant::toString () const

Теперь с полученным QString вы можете добавить действие в меню.

QAction * QMenu::addAction ( const QString & text )

То, что вы должны убедиться, что вы должны быть в состоянии пройти через все элементы в модели, чтобы вы могли получить индекс каждого и каждого элемента. Надеюсь, поможет..

Другие советы

К сожалению, нет QMenuView класс, но я нашел эту перспективную реализацию в сети: QMenuView (QMenuview.h., QMenuview.cpp.).

Чтобы ответить на ваш короткий вопрос, да, есть. Но вам придется написать это сами.

Простая часть будет создана подкласс QABSTRACTLISTMODEL.

Тяжелая часть была бы, когда вы создаете свой собственный вид. Qt позволит вам создать свой собственный вид, как если бы вы создали свою собственную модель, но это станет намного сложнее, так как вы должны обращаться все сами.

Это полностью выполняется для определенной цели, но это также гораздо больше работы, чем я думаю, вы хотите. Итак, как говорил Джанни, каркас моделей Qt Model-View не предназначен для использования таким образом.

Нет. Модели могут быть использованы только с видами, согласно Модель-вид Рамки, которые использует Qt.

Вы можете создать пункт меню и поставить QListView в него с использованием QWidgetAction. Отказ Конечно, это меню не может иметь подменю. Пример ниже находится в Python, но я надеюсь, что это не имеет значения в этом случае.

enter image description here

from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import Qt


class QListViewMenu(QtWidgets.QMenu):
    """
    QMenu with QListView.
    Supports `activated`, `clicked`, `doubleClicked`. `setModel`.
    """
    max_visible_items = 16

    def __init__(self, parent=None):
        super().__init__(parent)
        self.listview = lv = QtWidgets.QListView()
        lv.setFrameShape(lv.NoFrame)
        lv.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        pal = lv.palette()
        pal.setColor(pal.Base, self.palette().color(pal.Window))
        lv.setPalette(pal)
        lv.setEditTriggers(lv.NoEditTriggers)  # disable edit on doubleclick

        act_wgt = QtWidgets.QWidgetAction(self)
        act_wgt.setDefaultWidget(lv)
        self.addAction(act_wgt)

        self.activated = lv.activated
        self.clicked = lv.clicked
        self.doubleClicked = lv.doubleClicked
        self.setModel = lv.setModel

        lv.sizeHint = self.size_hint
        lv.minimumSizeHint = self.size_hint
        lv.mousePressEvent = lambda event: None  # skip
        lv.mouseMoveEvent = lambda event: None  # skip
        lv.mouseReleaseEvent = self.mouse_release_event

    def size_hint(self):
        lv = self.listview
        width = lv.sizeHintForColumn(0)
        width += lv.verticalScrollBar().sizeHint().width()
        if isinstance(self.parent(), QtWidgets.QToolButton):
            width = max(width, self.parent().width())
        visible_rows = min(self.max_visible_items, lv.model().rowCount())
        return QtCore.QSize(width, visible_rows * lv.sizeHintForRow(0))

    def mouse_release_event(self, event):
        if event.button() == Qt.LeftButton:
            idx = self.listview.indexAt(event.pos())
            if idx.isValid():
                self.clicked.emit(idx)
            self.close()
        super(QtWidgets.QListView, self.listview).mouseReleaseEvent(event)


class Form(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()
        words = "ability able about above accept according account across"
        model = QtCore.QStringListModel(words.split())
        # fake icons to take space
        def data(index, role):
            if role == Qt.DecorationRole:
                pixm = QtGui.QPixmap(40, 40)
                pixm.fill(Qt.transparent)
                return QtGui.QIcon(pixm)
            return QtCore.QStringListModel.data(model, index, role)
        model.data = data

        self.btn = btn = QtWidgets.QToolButton(self)
        btn.setText("QListView menu")
        btn.setPopupMode(btn.MenuButtonPopup)
        root_menu = QtWidgets.QMenu(btn)
        menu = QListViewMenu(btn)
        menu.setTitle('submenu')
        menu.setModel(model)
        menu.clicked.connect(self.item_clicked)
        root_menu.addMenu(menu)
        btn.setMenu(root_menu)

    def item_clicked(self, index):
        self.btn.menu().hide()
        print(index.data())

app = QtWidgets.QApplication([])
f = Form()
f.show()
app.exec()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top