問題描述
我想在 Qt 中制作一個表格,可以將其行折疊和展開成組(行按特定列的內(nèi)容分組),例如:
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.
我嘗試使用帶有 QTableWidget 的 QTreeView 作為子小部件,但是將表取消組合"到單個表中就成了問題.
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 并將組標題行"添加到表中.它有點工作,但正確實現(xiàn)它非常困難,因為它涉及移動行并插入這些假行",這些假行"的行為與其他行完全不同,從而弄亂了底層的 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.
有沒有更好的方法來實現(xiàn)這種小部件,或者可能已經(jīng)存在實現(xiàn)這種功能的標準 Qt 小部件?我認為我最終可以通過假行"(也許)使它與我當前的 QTableView 一起工作,但到目前為止,它很容易被破壞并且難以實現(xiàn),我真的想要一個更好的解決方案......
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 中將其行折疊成類別的表格?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!