Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从QAbstractTableModel类中访问视图和代理模型?_Python_Qt_Pyqt5_Pyside2 - Fatal编程技术网

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)