从QAbstractTableModel类中访问视图和代理模型?

时间:2018-02-01 12:46:47

标签: python qt pyqt5 pyside2

使用QTableViewQAbstractTableModel,我希望能够在表格中选择多个单元格,并进行编辑会影响所有选定的单元格。这就是我目前正在做的事情,包括将viewQTableView)和proxy_modelQSortFilterProxyModel)传递到类中,以便我可以访问它们(按顺序获取适当的行和列):

import sys
from pprint import pprint

try:
    from PySide2 import QtWidgets, QtCore
except ImportError:
    from PyQt5 import QtWidgets, QtCore


class MyTableModel(QtCore.QAbstractTableModel):
    def __init__(self,
                view,
                proxy_model,
                table_data,
                parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)

        self.table_data = table_data
        self.view = view
        self.proxy_model = proxy_model

    def rowCount(self, parent):
        return len(self.table_data)

    def columnCount(self, parent):
        return len(self.table_data[0])

    def flags(self, index):
        # Original, inherited flags:
        original_flags = super(MyTableModel, self).flags(index)

        return original_flags | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def data(self, index, role):
        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

        return None

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            row = index.row()
            column = index.column()

            selection_model = self.view.selectionModel()
            selected_indexes = selection_model.selectedIndexes()

            for selected_index in selected_indexes:

                mapped_index = self.proxy_model.mapToSource(selected_index)
                selected_row = mapped_index.row()
                selected_column = mapped_index.column()

                self.table_data[selected_row][selected_column] = value
                pprint(self.table_data)

                self.dataChanged.emit(index, selected_index)  # from, to

            return True

        return False


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

    table_data = [['one', 'two', 'three'], ['four', 'five', 'six']]

    view = QtWidgets.QTableView()
    proxy_model = QtCore.QSortFilterProxyModel()
    model = MyTableModel(view=view, proxy_model=proxy_model, table_data=table_data)

    proxy_model.setSourceModel(model)
    proxy_model.setDynamicSortFilter(True)

    view.setModel(proxy_model)
    view.setSortingEnabled(True)  # requires proxy model
    view.sortByColumn(0, QtCore.Qt.AscendingOrder)
    view.horizontalHeader().setStretchLastSection(True)
    view.horizontalHeader().setSectionsMovable(True)

    view.show()
    app.exec_()

我怀疑我不必将viewproxy_model传递给类,并且我可以通过其他方式访问这些对象。这是可能的,如果是的话 - 如何?

我知道我的示例是特定于Python的,但我的问题实际上是一个与绑定无关的问题,所以我也用qt标记了我的问题。

1 个答案:

答案 0 :(得分:1)

基本模型不应该知道视图或代理,因此您应该具有类似于以下内容的内容:

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)

代理有方法将更改传递给原始模型,因此通常没有必要访问基本模型来进行更改,但是相同的代理,订单我实现了一个小部件,我使用了{{ 1}}方法,这可能会导致无限循环,因此我们必须阻止其他dataChanged()信号,我们使用dataChanged()

blockSignals()

更新

似乎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_()) 有一个错误,因为它没有返回所选元素而是一个空列表,所以它不会进入for循环,在我们为它创建列表之前我们使用PySide2 selectionChanged的信号,这在PyQt5中不会发生。:

selectionModel()