如何制作一个可以将其行折叠到 Qt 中的类别的表格? [英] How can I make a table that can collapse its rows into categories in Qt?

查看:53
本文介绍了如何制作一个可以将其行折叠到 Qt 中的类别的表格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Qt中制作一个表格,可以将其行折叠和展开成组(行按特定列的内容分组),例如:

I want to make a table in Qt that can collapse and expand its rows into groups (the rows are grouped by the content of a specific column), such as this:

展开所有组:

第一组崩溃:

点击组标题行"时,所有子行"要么折叠到组标题行"中,要么显示在其下方.该表还应该能够自行取消分组"并成为普通表.

When clicking on the "group header rows", all "child rows" are either collapsed into the "group header row" or shown underneath it. The table should also be able to "un-group" itself and become a normal table.

我曾尝试将 QTreeView 与 QTableWidget 一起用作子小部件,但随后将表取消分组"到单个表中就成了一个问题.

I've tried using a QTreeView with QTableWidget as child widgets, but then it becomes a problem to "un-group" the tables into a single table.

我还尝试使用 QTableView 并将组标题行"添加到表格中.它有点工作,但正确实现它非常困难,因为它涉及移动行并插入这些行为与其余行为非常不同的假行",从而弄乱了底层的 QStandardItemModel.它还使排序变得异常复杂.

I also tried using QTableView and adding the "group header rows" to the table. It sort of works, but it has been very tough to implement it correctly, since it involves moving rows around and inserting these "fake rows" that behave very differently the rest, thus messing up the underlying QStandardItemModel. It also makes sorting unreasonably complicated.

有没有更好的方法来实现这种小部件,或者可能已经存在一个标准的 Qt 小部件来实现这种功能?我认为我最终可以让它与我当前的带有假行"的 QTableView 一起工作(也许),但到目前为止,它很容易崩溃并且难以实现,我真的想要一个更好的解决方案......

Is there any better way to implement this kind of widget, or maybe there already exists a standard Qt widget that implements this functionality? I reckon I can eventually make it work with my current QTableView with "fake rows" (maybe), but so far it has been so prone to breaking and hard to implement that I really want a better solution...

推荐答案

在这种情况下,应该使用 QTreeView,如下例所示:

In this case, a QTreeView should be used as shown in the following example:

from PyQt5 import QtCore, QtGui, QtWidgets

datas = {
    "Category 1": [
        ("New Game 2", "Playnite", "", "", "Never", "Not Played", ""),
        ("New Game 3", "Playnite", "", "", "Never", "Not Played", ""),
    ],
    "No Category": [
        ("New Game", "Playnite", "", "", "Never", "Not Plated", ""),
    ]
}

class GroupDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(GroupDelegate, self).__init__(parent)
        self._plus_icon = QtGui.QIcon("plus.png")
        self._minus_icon = QtGui.QIcon("minus.png")

    def initStyleOption(self, option, index):
        super(GroupDelegate, self).initStyleOption(option, index)
        if not index.parent().isValid():
            is_open = bool(option.state & QtWidgets.QStyle.State_Open)
            option.features |= QtWidgets.QStyleOptionViewItem.HasDecoration
            option.icon = self._minus_icon if is_open else self._plus_icon

class GroupView(QtWidgets.QTreeView):
    def __init__(self, model, parent=None):
        super(GroupView, self).__init__(parent)
        self.setIndentation(0)
        self.setExpandsOnDoubleClick(False)
        self.clicked.connect(self.on_clicked)
        delegate = GroupDelegate(self)
        self.setItemDelegateForColumn(0, delegate)
        self.setModel(model)
        self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.setStyleSheet("background-color: #0D1225;")

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def on_clicked(self, index):
        if not index.parent().isValid() and index.column() == 0:
            self.setExpanded(index, not self.isExpanded(index))


class GroupModel(QtGui.QStandardItemModel):
    def __init__(self, parent=None):
        super(GroupModel, self).__init__(parent)
        self.setColumnCount(8)
        self.setHorizontalHeaderLabels(["", "Name", "Library", "Release Date", "Genre(s)", "Last Played", "Time Played", ""])
        for i in range(self.columnCount()):
            it = self.horizontalHeaderItem(i)
            it.setForeground(QtGui.QColor("#F2F2F2"))

    def add_group(self, group_name):
        item_root = QtGui.QStandardItem()
        item_root.setEditable(False)
        item = QtGui.QStandardItem(group_name)
        item.setEditable(False)
        ii = self.invisibleRootItem()
        i = ii.rowCount()
        for j, it in enumerate((item_root, item)):
            ii.setChild(i, j, it)
            ii.setEditable(False)
        for j in range(self.columnCount()):
            it = ii.child(i, j)
            if it is None:
                it = QtGui.QStandardItem()
                ii.setChild(i, j, it)
            it.setBackground(QtGui.QColor("#002842"))
            it.setForeground(QtGui.QColor("#F2F2F2"))
        return item_root

    def append_element_to_group(self, group_item, texts):
        j = group_item.rowCount()
        item_icon = QtGui.QStandardItem()
        item_icon.setEditable(False)
        item_icon.setIcon(QtGui.QIcon("game.png"))
        item_icon.setBackground(QtGui.QColor("#0D1225"))
        group_item.setChild(j, 0, item_icon)
        for i, text in enumerate(texts):
            item = QtGui.QStandardItem(text)
            item.setEditable(False)
            item.setBackground(QtGui.QColor("#0D1225"))
            item.setForeground(QtGui.QColor("#F2F2F2"))
            group_item.setChild(j, i+1, item)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        model = GroupModel(self)
        tree_view = GroupView(model)
        self.setCentralWidget(tree_view)

        for group, childrens in datas.items():
            group_item = model.add_group(group)
            for children in childrens:
                model.append_element_to_group(group_item, children)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.resize(720, 240)
    w.show()
    sys.exit(app.exec_())

这篇关于如何制作一个可以将其行折叠到 Qt 中的类别的表格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆