如何在Qt或PyQt中使用QDataWidgetMapper?

How to use QDataWidgetMapper in Qt or PyQt?

我可以找到一些关于如何在标准视图中使用标准模型的示例。

http://doc.qt.io/qt-5/modelview.html

http://doc.qt.io/qt-5/qtwidgets-itemviews-simplewidgetmapper-example.html

但我找不到一个如何使用 QAbstractModel 制作我自己的 model 并自己使用它的示例 view/widget

更新模型后,展台视图会更新,但我自己的视图不会更新。

完整代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from  PyQt5.QtWidgets import (QWidget, QLabel, QDataWidgetMapper,
                              QLineEdit, QApplication, QGridLayout)
from PyQt5.QtCore import QAbstractListModel, Qt
from PyQt5.QtWidgets import QListView


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

        self.model = model

        # Set up the widgets.
        nameLabel = QLabel("Na&me:")
        nameEdit = QLineEdit()

        # Set up the mapper.
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(nameEdit, 0)

        layout = QGridLayout()
        layout.addWidget(nameLabel, 0, 0, 1, 1)
        layout.addWidget(nameEdit, 0, 1, 1, 1)
        self.setLayout(layout)

        self.mapper.toFirst()


class MyModel(QAbstractListModel):
    def __init__(self, status=[], parent=None):
        super().__init__(parent)
        self.status = status

    def rowCount(self, index_parent=None, *args, **kwargs):
        return len(self.status)

    def data(self, index, role=Qt.DisplayRole, parent=None):
        if not index.isValid():
            return None
        row = index.row()
        if row == 0:
            print(index)
            if role == Qt.DisplayRole:
                return self.status[row]
            elif role == Qt.EditRole:  # if it's editing mode, return value for editing

                return self.status[row]

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsEditable

    def setData(self, index, value='', role=Qt.EditRole):
        row = index.row()

        if role == Qt.EditRole:
            self.status[row] = value
            self.dataChanged.emit(index, index)  # inform the other view to request new data
            return True
        else:
            return False


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    myModel_on_mywindow = MyModel([1, 2, 3])
    mywindow = Window(myModel_on_mywindow)
    mywindow.setWindowTitle('myModel_on_mywindow')
    mywindow.show()
    myModel_on_mywindow.status[0] = 2

    myModel_on_qlistview = MyModel([1, 2, 3])
    qlistview = QListView()
    qlistview.show()
    qlistview.setModel(myModel_on_qlistview)
    qlistview.setWindowTitle('myModel_on_qlistview')

    myModel_on_qlistview.status[0] = 2

    sys.exit(app.exec_())

您的自定义模型需要覆盖抽象模型的某些功能,具体取决于您将哪个子类化。这是一个子类化 QAbstractListModel 的小例子。您可以在 Qt 文档中阅读更多相关信息:QAbstractListModel Details

class MyModel(QAbstractListModel):
    def __init__(parent=None):
        QAbstractListModel.__init__(parent)
        self.content = []  # holds the data, you want to present

    def rowCount(index):
        return len(self.content)
    # This defines what the view should present at given index
    def data(index, role):
        if index.isValid() and role == Qt.DisplayRole):
            dataElement = self.content[index.row()]
            if index.colum() == 0:
                return dataElement.someBoolField
            if index.colum() == 1:
                return dataElement.someIntField
            # ...
        }
        return QVariant()  # this is like returning nothing
    }
    # If your items should be editable. Automatically called, when user changes the item.
    def setData(index, value, role):
        if index.isValid():
            dataElement = self.content[index.row()].get()
            if index.column() == 0:
                return dataElement.tryToSetBoolField(value.toBool())
            if index.column() == 1:
                return dataElement.tryToSetIntField(value.toInt())
            # ...
        }
        return True
    }
};

# connecting your view with your model
model = MyModel()
myView = QTreeView()  # or something else
myView.setModel(model)

编辑

要在结合使用自定义模型和 QDataMapper 时更新您的视图,请在更改模型后调用 setCurrentIndex(changedIndex) 或其包装器,就像您的情况一样:

myModel_on_mywindow.status[0] = 2
myModel.mapper.toFirst()

QDataMapper 上的 Qt 文档在详细说明中提到了这一点:

The navigational functions toFirst(), toNext(), toPrevious(), toLast() and setCurrentIndex() can be used to navigate in the model and update the widgets with contents from the model.