使用模型作为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
) ?
解决方案
如果您的目标只是为了更新您的菜单acton 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会让您创建自己的视图,就像您要创建自己的模型一样,但是它会变得更加复杂,因为您必须处理 一切 你自己。
对于特定目的来说,这完全是可行的,但它的工作比您想的要多得多。因此,就像吉安尼(Gianni)所说的那样,QT的模型视图框架并不是要使用这种方式。
否。模型只能与视图一起使用 模型视图 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()