如何在PyQt6中实现嵌套QComboBox?

问题描述 投票:0回答:1

是否有一种简单的(我的意思是,无需重新实现太多成员)方法来使用 QComboBox 作为 QComboBox 项?

我想要实现的效果是一个普通的 QComboBox 在关闭时显示单个值,在打开时应显示正常列表;一些(或全部)列表项可以嵌套 QComboBox,可以打开它以选择树状逻辑中的嵌套条目。

关闭时,QComboBox 应仅显示(和 QSignal)所选子组合中的所选项目。

这可能吗(当然,无需重写整个小部件)?

我目前正在研究小部件委托,但我不确定这是否是正确的方法。

我正在使用 PyQt6(如果相关)。

qt pyqt nested qcombobox
1个回答
0
投票

我想出了一个可行的解决方案,但如果有的话,我完全愿意接受更好的想法。

这是我的测试程序:

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())
© www.soinside.com 2019 - 2024. All rights reserved.