我已经将QAbstractTableModel(使用PyQt4)子类化,包括setData方法。我的数据保存在嵌套列表中,列标题(" col_headers")和行标题(" row_headers)存储在列表中。如果相关,则行和列标题不是唯一的。
这里是init:
def __init__(self):
self.arraydata = [[]]
self.col_headers = [] # Columns
self.row_headers = [] # Rows
我已经实现了setData,如下所示(带有一些调试打印语句):
def setData(self, index, value, role=QtCore.Qt.EditRole):
row = index.row()
column = index.column()
print('row {} col {}'.format(row, col) # This gives the expected values
print('data before: {}'.format(self.arraydata) # The before state
self.arraydata[row][column] = value
print('data after: {}'.format(self.arraydata) # The after state = the problem
self.dataChanged.emit(index, index)
这通常在我第一次开始运行它时起作用,并且表格按预期填充,一次一个单元格。
但是,随着更多的setData调用通过,而不是仅更新特定项,它通常(但不总是)更新大多数或所有其他行的同一列的值。如果我的模型视图(QTableView)被滚动或调整大小,或者窗口被调整大小,这个问题会变得更糟(或者如果它还没有发生则触发)。
所以我的问题是,我如何在我的模型上设置数据,以便只更改模型中的一个项目?列表清单是我保存数据的正确方法吗?最后,问题可能是由于快速连续发生的过多发射引起的,随后的回调和#34;引擎盖下#34;通过对模型搞乱索引的看法?
完整(简化)代码:
from PyQt4 import QtCore, QtGui
ROWS = 0
COLS = 0
class MyTableModel(QtCore.QAbstractTableModel):
def updateData(self, row_header, col_header, value):
ix_to_chg = []
for i, row_h in enumerate(self.row_headers):
for j, col_h in enumerate(self.col_headers):
if row_h == row_header and col_h == col_header:
ix_to_chg.append((i, j))
for i, j in ix_to_chg:
index=self.index(i, j)
self.setData(index=index, value=value, role=QtCore.Qt.EditRole)
def insertRows(self, position, count, new_row_headers, parent=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), position, position + count -1)
empty_row = ['' for x in range(self.columnCount())]
for i in range(count):
self.arraydata.insert(position, empty_row)
new_row_header = new_row_headers[::-1][i]
self.row_headers.insert(position, new_row_header)
self.endInsertRows()
def insertColumns(self, position, count, new_col_headers, parent=QtCore.QModelIndex()):
self.beginInsertColumns(QtCore.QModelIndex(), position, position + count -1)
empty_cell = ''
for i in range(count):
self.arraydata[0].insert(position+i, empty_cell)
new_col_header = new_col_headers[i]
self.col_headers.insert(position + i, new_col_header)
self.endInsertColumns()
def setData(self, index, value, role=QtCore.Qt.EditRole):
row = index.row()
column = index.column()
print('row {} col {}'.format(row, column)) # This gives the expected values
print('data before: {}'.format(self.arraydata)) # The before state
self.arraydata[row][column] = value
print('data after: {}'.format(self.arraydata)) # The after state = the problem
self.dataChanged.emit(index, index)
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
i = index.row()
j = index.column()
return '{}'.format(self.arraydata[i][j])
else:
return None
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if self.columnCount() == 0:
return []
else:
return self.col_headers[section]
else:
if self.rowCount() == 0:
return []
else:
return self.row_headers[section]
def flags(self, index):
return QtCore.Qt.ItemIsEnabled
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata)-1
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata[0])
def setupModel(self, numRows, numCols):
for row_num in range(numRows):
for col_num in range(numCols):
if self.rowCount(self) < numRows:
for i in range(numRows - self.rowCount(self)):
self.arraydata.append([])
if self.columnCount(self) < numCols:
for i in range(numCols - self.columnCount(self)):
for j in range(self.rowCount(self)):
item = '_'.join(['row', str(j), 'col', str(i)])
self.arraydata[j].append(item)
def __init__(self, col_headers=None, row_headers=None, rows=ROWS, cols=COLS):
QtCore.QAbstractTableModel.__init__(self)
self.arraydata = [[]]
col_headers = ['emptyColHeader' for i in range(cols)] if col_headers is None else col_headers
row_headers = ['emptyRowHeader' for i in range(rows)] if row_headers is None else row_headers
self.col_headers = col_headers
self.row_headers = row_headers
编辑:
解决了它(感谢List of lists changes reflected across sublists unexpectedly)。
在insertRows()
中,我在循环中为每一行添加了相同的列表 - 它们都指的是相同的列表。该函数的新代码:
def insertRows(self, position, count, new_row_headers, parent=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), position, position + count -1)
empty_row = ['' for x in range(self.columnCount())]
for i in range(count):
self.arraydata.insert(position, empty_row.copy())
new_row_header = new_row_headers[::-1][i]
self.row_headers.insert(position, new_row_header)
self.endInsertRows()