我正在尝试使用QAbstractTableModel将数据从QDataWidgetMapper映射到自定义视图。映射器工作正常,但是映射的数据不会根据模型中的更改自动更新。我需要手动更改 currentMapperIndex 以触发自定义视图上的更改。
我试图最大程度地简化我的问题。
TableModel:
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
自定义视图:
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映射的数据没有更新,除非我手动更改用于更改映射器索引的Spinbox。
在QDataWidgetMapper文档中,我们可以阅读:
请注意,QDataWidgetMapper会跟踪外部修改。如果模型的内容在应用程序的另一个模块中更新,则小部件也将更新。
似乎并非如此...
即使以Qt C ++形式编写,任何帮助也将不胜感激。
编辑:
根据update
的答案对Kuba Ober
方法进行的更改:
def update(self, dataIn):
self.beginResetModel()
self.datatable = dataIn
self.endResetModel()
答案 0 :(得分:0)
您的模型没有履行每个Qt模型必须履行的合同。问题的一部分在于模型,而不是映射器。即,update
应该使用beginResetModel
和endResetModel
方法。您不应该自己发出布局更改信号。实际上,您应该从模型中发出的唯一预定义信号是dataChanged
-QAbstractItemModel
会发出其他信号,以响应对beginAction
和endAction
的调用。>
重置模型后,视图应重置当前索引-毕竟,在重置过程中,模型实际上没有行-并且当前索引变为无效。因此,将以下内容添加到CustomView.setModel
:
self.model.modelReset.connect(self.mapper.toFirst)
可以说,也许映射器应该自己建立这种连接,但事实并非如此,因此您必须这样做。