pyqt QAbstractTableModel实现setData更改错误项的值

时间:2016-10-27 04:35:15

标签: python pyqt4

我已经将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()

0 个答案:

没有答案