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