Verwenden Sie ein Modell als Quelle für einen QMenu
-
01-10-2019 - |
Frage
ich ein Modell erstellt, das die vorhandenen Konfigurationen auflisten (lassen Sie uns sagen, dass es „Dateien“ listet, da dies nicht wirklich hier Angelegenheit). Bisher funktioniert es gut, wenn sie ein QListView
befestigt ist.
Beispiel:
--- ListView ---
- file #1 -
- file #2 -
- file #3 -
- file #4 -
----------------
Ist es möglich, das gleiche Modell für eine dynamisch aktualisierte QMenu
zu benutzen?
So etwas wie:
Menu
-> Submenu #1
-> Submenu #2
-> File-submenu
-> file #1
-> file #2
-> file #3
-> file #4
-> Submenu #3
Kurz gesagt: Gibt es eine Möglichkeit, eine Liste von dynamicaly aktualisiert QAction
s zu erstellen (gruppierte in die gleiche QMenu
) in Abhängigkeit von einem Modell (von QAbstractListModel
abgeleitet)
Lösung
Wenn Ihr Ziel nur Ihr Menü Actons mit dem Artikeltext zu aktualisieren, die in den QAbstractListModel
verfügbar sind, dann ist die Antwort Ja.
Hier ist eine Art und Weise ..
Index des Einzel Element kann mithilfe der folgenden Funktion erhalten werden.
QModelIndex QAbstractListModel::index ( int row, int column = 0,
const QModelIndex & parent = QModelIndex() ) const [virtual]
Mit dem erhaltenen Index können die Daten erhalten werden, indem
QVariant QModelIndex::data ( int role = Qt::DisplayRole ) const
Dann wird der Text availalble im Index kann durch die Verwendung erhalten werden,
QString QVariant::toString () const
Jetzt mit dem erhaltenen QString Sie eine Aktion zum Menü hinzufügen können.
QAction * QMenu::addAction ( const QString & text )
Das, was Sie dafür sorgen müssen, ist, dass, sollten Sie in der Lage sein, alle zu durchqueren durch die Elemente in dem Modell, so dass Sie den Index der jede und jeder Punkt zu erhalten. Hoffe, es hilft ..
Andere Tipps
Leider gibt es keine QMenuView
Klasse, aber ich fand diese vielversprechende Umsetzung im Internet: QMenuView
( qmenuview.h , qmenuview.cpp ).
Ihre kurze Frage zu beantworten, ja, es gibt. Aber Sie werden sich, es zu schreiben haben.
Der einfache Teil eine Unterklasse von QAbstractListModel zu erstellen wäre.
Der schwierige Teil wäre, wenn Sie Ihre eigene Ansicht erstellen. Qt können Sie Ihre eigene Ansicht zu erstellen, genau wie wenn Sie Ihr eigenes Modell erstellen waren, aber es wäre so viel komplexer geworden, da Sie Griff haben alles selbst.
Es ist durchaus machbar für einen bestimmten Zweck, aber es ist auch viel mehr Arbeit, als ich glaube, Sie wollen. So, wie Gianni sagt, Qt-Modell-Ansicht Rahmen ist nicht dazu gedacht, auf diese Art und Weise verwendet werden.
Nein. Die Modelle können nur mit Ansichten verwendet werden, gemäß dem Model-View Rahmen, dass Qt Anwendungen.
Sie können einen Menüpunkt anlegen und QListView
hinein QWidgetAction
verwenden. Natürlich kann dieses Menü hat nicht Untermenü. Das folgende Beispiel ist in Python, aber ich hoffe, es spielt keine Rolle, in diesem Fall.
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()