Используйте модель в качестве источника для QMenu - PullRequest
5 голосов
/ 28 июня 2010

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

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

Ответы [ 5 ]

4 голосов
/ 23 августа 2011

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

1 голос
/ 29 июня 2010

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

Легкая часть заключается в создании подкласса QAbstractListModel.

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

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

1 голос
/ 29 июня 2010

Если ваша цель состоит в том, чтобы просто обновить свои элементы меню с помощью текста элемента, доступного в 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 )

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

0 голосов
/ 20 мая 2019

Вы можете создать пункт меню и поместить в него 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()
0 голосов
/ 28 июня 2010

Нет.Модели могут использоваться только с представлениями согласно Model-View фреймворку, который использует Qt.

...