使用 beginMoveColumns 在 QTableView (QAbstractTableModel) 中的列没有正确移动?

Posted

技术标签:

【中文标题】使用 beginMoveColumns 在 QTableView (QAbstractTableModel) 中的列没有正确移动?【英文标题】:Columns not properly moving in QTableView (QAbstractTableModel) using beginMoveColumns? 【发布时间】:2021-08-28 15:47:50 【问题描述】:

我正在尝试使用beginMoveColumnsQTableView 中移动单个列,但在下面的示例中它不能正常工作。单元格选择被打乱,列宽不移动。使用相同逻辑移动行似乎可以正常工作。我做错了什么?

视频:https://www.screencast.com/t/5UJ0iByZCEE

from PyQt5 import QtWidgets, QtCore, QtGui
import sys
from PyQt5.QtCore import QModelIndex, Qt


class MyTableModel(QtCore.QAbstractTableModel):
    def __init__(self, data=[[]], parent=None):
        super().__init__(parent)
        self.data = data

    def headerData(self, section: int, orientation: Qt.Orientation, role: int):
        if role == QtCore.Qt.DisplayRole:
            return "Header"

    def columnCount(self, parent=None):
        return len(self.data[0])

    def rowCount(self, parent=None):
        return len(self.data)

    def data(self, index: QModelIndex, role: int):
        if role == QtCore.Qt.DisplayRole:
            row = index.row()
            col = index.column()
            return str(self.data[row][col])

    def move_column(self, ix, new_ix):
        parent = QtCore.QModelIndex()
        if new_ix > ix:
            target = new_ix + 1
        else:
            target = new_ix
        self.beginMoveColumns(parent, ix, ix, parent, target)

        # Shift column in each row
        for row in self.data:
            row.insert(new_ix, row.pop(ix))

        self.endMoveColumns()

    def move_row(self, ix, new_ix):
        parent = QtCore.QModelIndex()
        if new_ix > ix:
            target = new_ix + 1
        else:
            target = new_ix
        self.beginMoveRows(parent, ix, ix, parent, target)

        # Shift row
        self.data.insert(new_ix, self.data.pop(ix))

        self.endMoveRows()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    data = []
    for i in range(12):
        row = []
        data.append(row)
        for j in range(6):
            row.append(f"Ri_Cj")

    model = MyTableModel(data)
    view = QtWidgets.QTableView()
    view.setModel(model)

    view.setColumnWidth(0, 50)
    view.setColumnWidth(1, 100)

    view.setRowHeight(0, 50)
    view.setRowHeight(1, 100)

    container = QtWidgets.QWidget()
    layout = QtWidgets.QVBoxLayout()
    container.setLayout(layout)

    layout.addWidget(view)

    button = QtWidgets.QPushButton("Move 1st column right by 1")
    button.clicked.connect(lambda: model.move_column(0, 1))
    layout.addWidget(button)

    button = QtWidgets.QPushButton("Move 1st column right by 2")
    button.clicked.connect(lambda: model.move_column(0, 2))
    layout.addWidget(button)

    button = QtWidgets.QPushButton("Move 1st row down by 1")
    button.clicked.connect(lambda: model.move_row(0, 1))
    layout.addWidget(button)

    button = QtWidgets.QPushButton("Move 1st row down by 2")
    button.clicked.connect(lambda: model.move_row(0, 2))
    layout.addWidget(button)

    container.resize(800, 800)
    container.show()


    sys.exit(app.exec_())

【问题讨论】:

我试图了解奇怪的选择行为,因为它可能是一个错误。也就是说,标题的行为是预期的:移动行或列不会更改行和列的索引(因此,标题部分):您正在移动内部数据,而不是“实际”行/列索引.如果您需要移动显示的顺序,那么您不应该更改数据模型,而是移动标题部分(使用header.moveSection())。 嗯,我的误解可能比我想象的要多。 QAtbstractTableModel 不应该也处理移动标题数据吗?我的目标是完全移动列和行(单元格数据和标题数据)。这种移动应该是对底层数据的修改,应该反映在视图中,并且我希望列和行大小跟随数据。这是我使用 Excel 执行我描述的操作的片段screencast.com/t/uajgleiH 另一件重要的事情(与上一篇一样对您的原始帖子有效),您不应将数据引用命名为self.datadata() 是访问数据模型所调用的方法(并且可以通过model.data() 访问),所以它应该被覆盖。 带有“...不是标准行为” 我指的是移动基础数据行/列时 headers 的移动。虽然我可以理解您的观点,但这不是 Qt 项目模型的基本实现的工作方式。您可以通过在移动行/列时重新排序标题列表来提供该功能,类似于reindex 所做的。关于这一点:由于数据帧返回的索引的类型,标题变得不可见;重新索引会导致标题变成 int64 类型,而 PyQt 对这种类型一无所知:使用 int() 来解决这个问题。 让我们continue this discussion in chat。 【参考方案1】:

原来这是一个错误,我在这里做了一个错误报告:https://bugreports.qt.io/browse/QTBUG-94503

作为一种解决方法,我只是在列移动时清除单元格选择,并使用这个 sn-p 来移动列宽

model = view.model()
column_widths = [view.columnWidth(ix) for ix in range(model.columnCount())]
column_widths.insert(new_ix, column_widths.pop(ix))

# Set width of destination column to the width of the source column
for j in range(len(column_widths)):
    view.setColumnWidth(j, column_widths[j])

【讨论】:

以上是关于使用 beginMoveColumns 在 QTableView (QAbstractTableModel) 中的列没有正确移动?的主要内容,如果未能解决你的问题,请参考以下文章

QTableWidget表头样式

Qtablewidget设置颜色交替

BestMPRBaseVtk-004-搬运 vtkImageViewer2

Raspberry Pi 整点报时

oracle linux 安装Oracle Database 11gR2

在 spark 上使用集群和在本地使用并行操作有啥区别?