Python 如何使用beginMoveRows移动QTableView(QAbstractTableModel)中的行?

Python 如何使用beginMoveRows移动QTableView(QAbstractTableModel)中的行?,python,pyqt,qtableview,qabstracttablemodel,Python,Pyqt,Qtableview,Qabstracttablemodel,在下面的示例中,我试图在QTableView中移动行,但我很难理解如何正确调用beginMoveRows。我的示例有3个按钮来执行各种行移动,第3个按钮(向下移动一行1)导致程序崩溃 我认为它崩溃是因为这句话 请注意,如果sourceParent和destinationParent相同,则必须确保destinationChild不在sourceFirst和sourceLast+1的范围内。您还必须确保不尝试将行移动到其自己的子行或祖先行之一。如果任一条件为true,则此方法返回false,在这种

在下面的示例中,我试图在QTableView中移动行,但我很难理解如何正确调用
beginMoveRows
。我的示例有3个按钮来执行各种行移动,第3个按钮(向下移动一行1)导致程序崩溃

我认为它崩溃是因为这句话

请注意,如果sourceParent和destinationParent相同,则必须确保destinationChild不在sourceFirst和sourceLast+1的范围内。您还必须确保不尝试将行移动到其自己的子行或祖先行之一。如果任一条件为true,则此方法返回false,在这种情况下,您应该中止移动操作

但是这个限制不是意味着我不能将一行向下移动1吗?在我的例子中,sourceLast==sourceFirst,因为我一次只移动一行,所以这个语句基本上说我的目标索引不能等于我的源索引+1,这是将一行向下移动1的定义。我是否误解了这些论点的意思?在本例中,如何将行向下移动1个位置

从PyQt5导入QtWidgets、QtCore、QtGui
导入系统
从PyQt5.QtCore导入QModelIndex,Qt
类MyTableModel(QtCore.QAbstractTableModel):
def uuu init(self,data=[[]],parent=None):
super()。\uuuu init\uuuu(父级)
self.data=数据
def headerData(自身,部分:int,方向:Qt.方向,角色:int):
如果角色==QtCore.Qt.DisplayRole:
如果方向=Qt.水平:
返回“列”+str(节)
其他:
返回“行”+str(节)
def columnCount(自身,父项=无):
返回len(自身数据[0])
def行数(自身,父项=无):
返回长度(自身数据)
def数据(self,索引:QModelIndex,角色:int):
如果角色==QtCore.Qt.DisplayRole:
行=索引。行()
col=index.column()
返回str(self.data[行][列])
类MyTableView(QtWidgets.QTableView):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
def移动_行(自身、ix、新_ix):
完整索引=self.model().index(0,self.model().rowCount())
self.model().beginMoveRows(完整索引,ix,ix,完整索引,新索引)
data=self.model().data
data.insert(新的_ix,data.pop(ix))
self.model().endMoveRows()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app=qtwidts.QApplication(sys.argv)
数据=[[11,12,13,14,15],
[21, 22, 23, 24, 25],
[31, 32, 33, 34, 35],
[41, 42, 43, 44, 45],
[51, 52, 53, 54, 55],
[61, 62, 63, 64, 65]]
模型=MyTableModel(数据)
视图=MyTableView()
view.setModel(model)
container=qtwidts.QWidget()
layout=qtwidts.QVBoxLayout()
container.setLayout(布局)
layout.addWidget(视图)
button=QtWidgets.QPushButton(“向下移动第三行2”)
按钮。单击。连接(lambda:view.move_行(2,2+2))
layout.addWidget(按钮)
button=QtWidgets.QPushButton(“将第三行向上移动1”)
按钮。点击。连接(lambda:view.move_行(2,2-1))
layout.addWidget(按钮)
button=QtWidgets.QPushButton(“将第三行向下移动1(此操作失败)”)
按钮。单击。连接(lambda:view.move_行(2,2+1))
layout.addWidget(按钮)
container.show()
sys.exit(app.exec_())

您应该注意文档的另一部分:

但是,当向下移动同一父级中的行时(sourceParent和destinationParent相等),这些行将放在destinationChild索引之前。也就是说,如果希望移动行0和1,使它们成为行1和2,destinationChild应该是3。在本例中,源行i(位于sourceFirst和sourceLast之间)的新索引等于(destinationChild-sourceLast-1+i)

您的解决方案不考虑这一点,您可以清楚地看到,如果选择第三行,然后尝试使用第一个按钮:当数据被正确移动时,选择不是。

在您的例子中,因为您移动的是一行,所以解决方案很简单:如果移动到底部,则添加1。还要注意,您应该使用父级,对于表模型,父级始终是无效的QModelIndex

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

        data = self.model().data
        data.insert(new_ix, data.pop(ix))

        self.model().endMoveRows()

考虑到,为了更好地遵守OOP的模块性,您应该在模型类中而不是在视图中创建适当的函数。

谢谢!我读了那一段,但误解了,我很感激你的帮助嗨,你能看看我编辑的问题吗?我最终遇到了一个类似的障碍,将完全相同的东西应用于列而不是行,但不知道为什么。我不想提出一个与我第一个问题如此相似的新问题one@Esostack不,不!你不能完全改变一个问题,特别是在给出答案并且你也接受了答案之后。我的回答现在有什么意义?想象一个用户有一个与你的“新”问题类似的问题,他们怎么知道我的答案不是针对这个问题的?我现在应该改变我的答案吗?如果其他人回答了你的“新”问题,那么你应该接受哪一个?您必须记住,StackOverflow不仅仅适用于单个用户,也适用于社区:问题和答案应该对每个人都有帮助。创建一个新问题,我已经回滚了您的问题。@musicmante好的,我的错,我认为行和列的解决方案可能非常相似,因为这两种方法有相同的文档。我要做一个新的one@Esostack它们相似的事实并不重要:您最初的问题和我的答案涉及行移动,这需要不同的方法调用和过程来更改内部数据的列顺序;这将使我的答案无效,一个没有经验的用户可能不知道其中的区别,他们可能会被引导相信我的答案是有效的。如果您需要澄清类似问题,请使用