如何在Qt或PyQt中使用QDataWidgetMapper?

时间:2015-07-04 13:51:57

标签: python qt user-interface model-view-controller pyqt

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

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

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

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

更新模型后,立场视图将更新,但不会更新我自己的视图。run result

完整代码:

#!/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_())

1 个答案:

答案 0 :(得分:3)

您的自定义模型需要覆盖抽象模型的某些函数,具体取决于您子类的哪一个。这是子类化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文档在详细说明中提到了这一点:

  

导航函数toFirst(),toNext(),toPrevious(),toLast()和setCurrentIndex()可用于在模型中导航并使用模型中的内容更新小部件