问题描述
我有一个简单的示例:QAbstractTableModel的最后一列中的值等于第1列中的值乘以2。因此,每次对第1列中的值进行更改时,都会导致第2列中的更改。
最后一列的值更改后,将显示一个消息框,询问用户是否希望确认操作。
想象用户在第1列中更改了值并看到以下消息:如果希望单击“取消”(返回第1列和第2列中的两个旧值),我希望我的应用撤消更改,您能帮我吗?我需要定义我的“ go_back()”函数:
class Mainwindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.table = QtWidgets.QTableView()
self.setCentralWidget(self.table)
self.data = [
[1,0.18,0.36],[2,0.25,0.50],[3,0.43,0.86],]
self.model = MyModel(self.data)
self.table.setModel(self.model)
self.table.setSelectionBehavior(self.table.SelectRows)
self.table.setSelectionMode(self.table.SingleSelection)
self.model.dataChanged.connect(lambda index: self.count_last_column(index))
self.model.dataChanged.connect(lambda index: self.if_last_column_changed(index))
def calculations(self,position):
value = self.model.list_data[position][1] * 2
return value
def count_last_column(self,index):
if index.column() == 1:
position = index.row()
self.model.setData(self.model.index(position,2),self.calculations(position))
def if_last_column_changed(self,index):
if index.column() == 2:
message_Box,message_Box_button = self.show_message_Box()
if message_Box_button == 'Ok':
pass
elif message_Box_button == 'Cancel':
self.go_back()
def show_message_Box(self):
self.message_Box = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning,'Action','Value in column 3 has changed,confirm action?')
self.message_Box.Ok = self.message_Box.addButton(QtWidgets.QMessageBox.Ok)
self.message_Box.Cancel = self.message_Box.addButton(QtWidgets.QMessageBox.Cancel)
self.message_Box.exec()
if self.message_Box.clickedButton() == self.message_Box.Ok:
return (self.message_Box,'Ok')
elif self.message_Box.clickedButton() == self.message_Box.Cancel:
return (self.message_Box,'Cancel')
def go_back(self):
pass #################
class MyModel(QtCore.QAbstractTableModel):
def __init__(self,list_data = [[]],parent = None):
super(MyModel,self).__init__()
self.list_data = list_data
def rowCount(self,parent):
return len(self.list_data)
def columnCount(self,parent):
return len(self.list_data[0])
def data(self,index,role):
if role == QtCore.Qt.displayRole:
row = index.row()
column = index.column()
value = self.list_data[row][column]
return value
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
value = self.list_data[row][column]
return value
def setData(self,value,role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
self.list_data[row][column] = value
self.dataChanged.emit(index,index)
return True
return False
def flags(self,index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
if __name__ == '__main__':
app = QtWidgets.QApplication([])
application = Mainwindow()
application.show()
sys.exit(app.exec())
解决方法
一种选择是将QUndoStack与项目模型一起使用,并将QUndoCommand对象推入setData
中的堆栈中。这种方法的好处是,如果需要,可以轻松实现更多的撤消/重做控件。
在MyModel
中,只需在构造函数中创建一个堆栈,然后添加一行以在修改列表数据之前将命令推入堆栈(这样就可以将先前的值存储在命令中)。该课程的其余部分保持不变。
class MyModel(QtCore.QAbstractTableModel):
def __init__(self,list_data = [[]],parent = None):
super(MyModel,self).__init__()
self.list_data = list_data
self.stack = QtWidgets.QUndoStack()
def setData(self,index,value,role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
self.stack.push(CellEdit(index,self))
self.list_data[row][column] = value
self.dataChanged.emit(index,index)
return True
return False
使用传递给构造函数的索引,值和模型创建QUndoCommand,以便可以通过调用undo或redo来修改所需的单元格。
class CellEdit(QtWidgets.QUndoCommand):
def __init__(self,model,*args,**kwargs):
super().__init__(*args,**kwargs)
self.index = index
self.value = value
self.prev = model.list_data[index.row()][index.column()]
self.model = model
def undo(self):
self.model.list_data[self.index.row()][self.index.column()] = self.prev
def redo(self):
self.model.list_data[self.index.row()][self.index.column()] = self.value
现在go_back
中需要做的就是对两个已修改的单元格调用两次undo方法。
def go_back(self):
self.model.stack.undo()
self.model.stack.undo()