python - 更新 Qt QDataWidgetMapper 上的数据,同时映射器索引保持不变

标签 python pyqt

我正在尝试映射 QAbstractTableModel 中的数据使用 QDataWidgetMapper 到自定义 View 。映射器工作正常,但映射的数据不会根据模型的变化自动更新。我需要手动更改 currentMapperIndex 以触发自定义 View 上的更改。

我试图最大限度地简化我的问题。

表格模型:

class TableModel(QAbstractTableModel):
    def __init__(self, parent=None):
        super(TableModel, self).__init__(parent)
        self.columns = ['Col1', 'Col2']
        self.datatable = []

    def update(self, dataIn):
        self.layoutAboutToBeChanged.emit()
        self.datatable = dataIn
        self.layoutChanged.emit()

    def rowCount(self, parent=QModelIndex()):
        return len(self.datatable)

    def columnCount(self, parent=QModelIndex()):
        return len(self.columns)

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.columns[section].title()

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole or role == Qt.EditRole:
            row = self.datatable[index.row()]
            column_key = self.columns[index.column()]
            return row[column_key]
        else:
            return None

    def setData(self, index, value, role=Qt.EditRole):
        if not index.isValid() or role != Qt.EditRole:
            return False
        if self.datatable:
            column_key = self.columns[index.column()]

            self.datatable[index.row()][column_key] = value
            self.dataChanged.emit(index, index, [])
            return True
        return True
<小时/>

自定义 View :

class CustomView(QWidget):
    def __init__(self, parent=None):
        super(CustomView, self).__init__(parent)

        self.setupLayout()
        self.spinboxMapperIndex.valueChanged.connect(self.changeMapperIndex)

    def setModel(self, model):
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(model)
        self.mapper.addMapping(self.lineEdit1, 0)
        self.mapper.addMapping(self.lineEdit2, 1)
        self.mapper.toFirst()

    def changeMapperIndex(self, index):
        self.mapper.setCurrentIndex(index)

    def setupLayout(self):

        self.spinboxMapperIndex = QSpinBox()

        self.lineEdit1 = QLineEdit()
        self.lineEdit2 = QLineEdit()

        layout = QVBoxLayout()
        layout.addWidget(self.spinboxMapperIndex)
        layout.addWidget(self.lineEdit1)
        layout.addWidget(self.lineEdit2)
        self.setLayout(layout)
<小时/>

主要:

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

    model = TableModel()

    table = QTableView()
    table.setModel(model)
    table.show()

    data = [ {'Col1': 11, 'Col2': 12},
             {'Col1': 21, 'Col2': 22},
             {'Col1': 31, 'Col2': 32}]
    model.update(data)

    view = CustomView()
    view.setModel(model)
    view.show()

    newData = [ {'Col1': 111, 'Col2': 112},
                {'Col1': 121, 'Col2': 122},
                {'Col1': 131, 'Col2': 132}]
    model.update(newData)

    sys.exit(app.exec_())
<小时/>

通过运行上面的代码,可以看到 TableView 已使用新数据进行了很好的更新,而 CustomView 映射数据则不会更新,除非我手动更改旋转框以更改映射器索引。

关于QDataWidgetMapper我们可以阅读的文档:

Note that QDataWidgetMapper keeps track of external modifications. If the contents of the model are updated in another module of the application, the widgets are updated as well.

事实似乎并非如此...

任何帮助,即使是用 Qt C++ 形式编写的,我们都将不胜感激。

编辑:

根据 Kuba Ober 答案对 update 方法进行更改:

def update(self, dataIn):
    self.beginResetModel()
    self.datatable = dataIn
    self.endResetModel()

最佳答案

您的模型没有履行每个 Qt 模型必须履行的契约(Contract)。部分问题在于模型,而不在于映射器。即,update 应该使用 beginResetModelendResetModel 方法。您不应该自己发出布局更改信号。事实上,您应该从模型中自己发出的唯一预定义信号是 dataChanged - 其他信号由 QAbstractItemModel 发出,以响应对 beginAction 的调用和endAction

重置模型后, View 应该重置当前索引 - 毕竟,在重置期间,模型实际上没有行 - 并且当前索引变得无效。因此,将以下内容添加到 CustomView.setModel:

self.model.modelReset.connect(self.mapper.toFirst)

可以说,也许映射器应该自己建立这样的连接,但它没有 - 因此你必须这样做。

关于python - 更新 Qt QDataWidgetMapper 上的数据,同时映射器索引保持不变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52609229/

相关文章:

python - 如何使用用于 python-tornado 的 Facebook graph api 读取 facebook 用户的电子邮件?

python - QProgressBar 与 PyQt4 的奇怪行为

python - QSortFilterProxyModel.mapToSource 崩溃。没有信息为什么

Qt/PyQt(/其他?): How do I change specific colors in a pixmap?

python - 去除标点符号,输出剩余文本-Python 3 Function

python - Seaborn - 从 DataFrame 直方图中删除间距

python - 在 QDialog 中显示子进程的实时输出

python - 在 QMainWindows 中央小部件中的小部件之间切换

python - Pandas - 根据索引结果返回 pandas 中的相邻列

python - Scipy Curve_fit。多个参数的单独界限