是否有一种简单的(我的意思是,无需重新实现太多成员)方法来使用 QComboBox 作为 QComboBox 项?
我想要实现的效果是一个普通的 QComboBox 在关闭时显示单个值,在打开时应显示正常列表;一些(或全部)列表项可以嵌套 QComboBox,可以打开它以选择树状逻辑中的嵌套条目。
关闭时,QComboBox 应仅显示(和 QSignal)所选子组合中的所选项目。
这可能吗(当然,无需重写整个小部件)?
我目前正在研究小部件委托,但我不确定这是否是正确的方法。
我正在使用 PyQt6(如果相关)。
我想出了一个可行的解决方案,但如果有的话,我完全愿意接受更好的想法。
这是我的测试程序:
from PyQt6.QtCore import Qt, QAbstractItemModel, QModelIndex
main_course = {
'meat': {
'steak': 'steak',
'meatballs': 'meatballs',
},
'fish': {
'cod': 'cod',
'mullet': 'mullet',
'scallops': 'scallops'
},
'vegetarian': {
'salad': {
'mixed': 'mixed',
'cesar': 'cesar'
},
'flan': 'flan'
}
}
class TreeNode(object):
def __init__(self, label, parent):
self._label = label
self._parent = parent
self._child = []
def add_child(self, item):
self._child.append(item)
def child(self, row):
return self._child[row]
def index(self, child):
return self._child.index(child)
def childCount(self):
return len(self._child)
def columnCount(self):
return 1
def data(self, column):
if self._label is None:
if column == 0:
return 'Label'
else:
if column == 0:
return self._label
return None
def parent(self):
return self._parent
def row(self):
if self._parent:
return self._parent.index(self)
return 0
class TreeModel(QAbstractItemModel):
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = TreeNode(None, None)
self.parents = {0: self.rootItem}
self.setup_model_data(main_course, self.rootItem)
def columnCount(self, parent=None):
if parent and parent.isValid():
return parent.internalPointer().columnCount()
else:
return 1
def data(self, index, role=...):
if not index.isValid():
return None
item = index.internalPointer()
if role == Qt.ItemDataRole.DisplayRole:
return item.data(index.column())
if role == Qt.ItemDataRole.UserRole:
if item:
return item.label
return None
def headerData(self, section, orientation, role=...):
if (orientation == Qt.Orientation.Horizontal and
role == Qt.ItemDataRole.DisplayRole):
try:
return ("Main course", "Given Name")[section]
except IndexError:
pass
return None
def index(self, row, column, parent=...):
if not self.hasIndex(row, column, parent):
return QModelIndex()
if not parent.isValid():
parent = self.rootItem
else:
parent = parent.internalPointer()
child = parent.child(row)
if child:
return self.createIndex(row, column, child)
else:
return QModelIndex()
def parent(self, index):
if not index.isValid():
return QModelIndex()
child = index.internalPointer()
if not child:
return QModelIndex()
parent = child.parent()
if parent == self.rootItem:
return QModelIndex()
return self.createIndex(parent.row(), 0, parent)
def rowCount(self, parent=...):
if parent.column() > 0:
return 0
if not parent.isValid():
item = self.rootItem
else:
item = parent.internalPointer()
return item.childCount()
def setup_model_data(self, data: dict, parent=None):
for k, v in data.items():
ti = TreeNode(k, parent)
if isinstance(v, dict):
self.setup_model_data(v, ti)
if parent:
parent.add_child(ti)
if __name__ == '__main__':
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QComboBox, QTreeView
app = QApplication(sys.argv)
mw = QWidget()
lo = QVBoxLayout()
wh = QComboBox()
tv = QTreeView()
wh.setView(tv)
wh.setModel(TreeModel())
lo.addWidget(wh)
mw.setLayout(lo)
mw.show()
sys.exit(app.exec())