Python 从QAbstractTableModel类中访问视图和代理模型?
使用Python 从QAbstractTableModel类中访问视图和代理模型?,python,qt,pyqt5,pyside2,Python,Qt,Pyqt5,Pyside2,使用QTableView和QAbstractTableModel,我希望能够在一个表中选择多个单元格,并对所有选定的单元格进行编辑。我目前就是这样做的,这涉及到将视图(QTableView)和proxy\u model(QSortFilterProxyModel)传递到类中,以便我可以访问它们(以便获取适当的行和列): 我怀疑我不必将view和proxy\u model传递到类中,我可以通过其他方式访问这些对象。这可能吗?如果可能,怎么可能 我知道我的示例是特定于Python的,但我的问题实际
QTableView
和QAbstractTableModel
,我希望能够在一个表中选择多个单元格,并对所有选定的单元格进行编辑。我目前就是这样做的,这涉及到将视图
(QTableView
)和proxy\u model
(QSortFilterProxyModel
)传递到类中,以便我可以访问它们(以便获取适当的行和列):
我怀疑我不必将view
和proxy\u model
传递到类中,我可以通过其他方式访问这些对象。这可能吗?如果可能,怎么可能
我知道我的示例是特定于Python的,但我的问题实际上是一个绑定不可知的问题,因此我也用
qt
标记我的问题,基本模型不应该知道视图或代理,因此您应该有类似于以下内容的内容:
class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, table_data, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.table_data = table_data
def rowCount(self, parent):
return len(self.table_data)
def columnCount(self, parent):
return len(self.table_data[0])
def flags(self, index):
original_flags = super(MyTableModel, self).flags(index)
return original_flags | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
item = index.internalPointer()
if item is not None:
print(item)
value = self.table_data[row][column]
return value
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
self.table_data[row][column] = value
self.dataChanged.emit(index, index)
return True
return QtCore.QAbstractTableModel.setData(self, index, value, role)
代理具有将更改传递到原始模型的方法,因此通常不需要访问基础模型来进行更改,而是使用同一个代理,为了获得订单,我实现了一个小部件,并使用了dataChanged()
方法,这可能会导致无限循环,因此我们必须阻止其他dataChanged()
信号我们使用blockSignals()
更新:
似乎PySide2
有一个bug,因为它不返回所选元素,而是一个空列表,所以它不会进入for循环,在我们为它创建该列表之前,我们使用selectionModel()
的selectionChanged
信号,这在PyQt5中不会发生
class Widget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
[...]
self.view.horizontalHeader().setSectionsMovable(True)
self.view.selectionModel().selectionChanged.connect(self.on_selectionChanged)
self.currentSelected = []
def on_selectionChanged(self, selected, deselected):
for ix in selected.indexes():
if ix not in self.currentSelected:
self.currentSelected.append(ix)
for ix in deselected.indexes():
if ix in self.currentSelected:
self.currentSelected.remove(ix)
def on_data_changed(self, _from, _to):
model = _from.model() # proxy model
model.blockSignals(True)
pindexes = [QtCore.QPersistentModelIndex(ix) for ix in self.currentSelected]
for index in pindexes:
model.setData(index, _from.data())
model.blockSignals(False)
QAbstractTableModel类不应该知道代理,只是代理的目的不是修改基础模型,而是将代理用作中介。我认为您不了解代理的使用。您可以解释一下使用代理和表的目的是什么。我认为您遇到的是设计问题,而不是访问问题。我的目标是能够选择多个单元格,输入一个新值,并将该值填充到所有选定的单元格中。如果没有视图(检测“多重选择”)和proxymodel(适当地映射单元格,以防它们被排序/过滤),我无法实现这一点@eyllanesc我意识到数据模型不应该知道视图或代理,因此我的问题是,您不必在模型的代码中执行该任务。如何输入数据?您有表单吗?您必须创建一个函数,从中获取所选单元格并使用函数setData(),不应覆盖setData()方法。你有一个设计问题,如果你想让我们帮助你,你必须提供你的背景问题。我强调,您不应该修改setData方法来执行该任务。@eyllanesc好的,我更新了代码。如果运行该选项,则可以选择多个单元格,输入新值并按enter键。该值将填充到您选择的每个单元格中,并更新基础的
表_数据
列表。保持排序和筛选。这就是我需要的行为。但是我不想把视图和代理模型传递给我的表模型…哇,我希望我能给你更多的投票权。最后一个问题是,在“更改数据”方法中,如何访问模型的“表数据”?我希望阅读它,以便在编辑完表后将其传递给程序的其余部分。一般来说,您不应该直接访问表_数据,但如果您想这样做,您应该执行以下操作:model.sourceModel().table_data
我找到了它。我将Widget.model
重命名为self.model,并通过调用self.model.table\u data
从中访问它。再次非常感谢!啊,model.sourceModel().table_data
更好。“不应直接访问”是什么意思?想象一下,例如,在这个表格下面有一个“提交”按钮,这样表格的内容就可以提交到其他功能中。这就是我想要做的。适当的做法是创建一个模型的方法,返回一个副本,因为如果直接修改表数据,模型将无法实现它。
class Widget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
QtWidgets.QWidget.__init__(self, *args, **kwargs)
self.view = QtWidgets.QTableView()
self.setLayout(QtWidgets.QVBoxLayout())
self.layout().addWidget(self.view)
table_data = [['one', 'two', 'three'], ['four', 'five', 'six']]
proxy_model = QtCore.QSortFilterProxyModel()
model = MyTableModel(table_data=table_data)
proxy_model.setSourceModel(model)
proxy_model.setDynamicSortFilter(True)
self.view.setModel(proxy_model)
proxy_model.dataChanged.connect(self.on_data_changed)
self.view.setSortingEnabled(True) # requires proxy model
self.view.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.view.horizontalHeader().setStretchLastSection(True)
self.view.horizontalHeader().setSectionsMovable(True)
def on_data_changed(self, _from, _to):
model = _from.model() # proxy model
model.blockSignals(True)
for index in self.view.selectionModel().selectedIndexes():
model.setData(index, _from.data())
model.blockSignals(False)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
class Widget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
[...]
self.view.horizontalHeader().setSectionsMovable(True)
self.view.selectionModel().selectionChanged.connect(self.on_selectionChanged)
self.currentSelected = []
def on_selectionChanged(self, selected, deselected):
for ix in selected.indexes():
if ix not in self.currentSelected:
self.currentSelected.append(ix)
for ix in deselected.indexes():
if ix in self.currentSelected:
self.currentSelected.remove(ix)
def on_data_changed(self, _from, _to):
model = _from.model() # proxy model
model.blockSignals(True)
pindexes = [QtCore.QPersistentModelIndex(ix) for ix in self.currentSelected]
for index in pindexes:
model.setData(index, _from.data())
model.blockSignals(False)