استخدم نموذجًا كمصدر لـ 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
) ?
المحلول
إذا كان هدفك هو مجرد تحديث قائمتك 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
. بالطبع لا يمكن أن تحتوي هذه القائمة على قوائم فرعية. المثال أدناه موجود في بيثون ، لكنني آمل ألا يهم في هذه الحالة.
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()