モデルを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
要するに、Dynamicalyの更新のリストを作成する方法はありますか QAction
S(同じにグループ化されています QMenu
)aに依存します モデル (に由来する QAbstractListModel
) ?
解決
あなたの目的が、で利用可能なアイテムテキストでメニューのactonsを更新することだけである場合 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のモデルビューフレームワークはこのように使用することを意図していません。
いいえ。モデルはビューでのみ使用できます。 モデルビュー 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()