使用PyQt创建自定义抽象小部件

3
我现在已经做了几个PyQt项目,并且对Qt采用的模型/视图思想变得更加熟悉。我已经将其用于类似于列表和表视图的东西,使用自定义模型在它们后面显示和操作数据。我使用委托编辑每个单元格/行中的基本信息。
如何在Qt中抽象这个模型/视图架构以消除对表/列表的需要?直接到编辑委托。
直观地说,可以这样做:
其中,一行的编辑触发器会打开一个委托,如下所示:
我想要转移到更像这样的东西,其中与thing1、thing2和另一件事相对应的对象不是静态的,并且可以在多个视图之间共享。就像使用QAbstractModel和QTableView一样。
1个回答

2
你可以使用QtGui.QDataWidgetMapper。请看下面这个例子的运行情况:

QtGui.QDataWidgetMapper

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

#---------
# IMPORT
#---------
import sys

import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)

from PyQt4 import QtGui, QtCore

#---------
# DEFINE
#---------
class MyItemDelegate(QtGui.QItemDelegate):
    def __init__(self, parent=None):
        super(MyItemDelegate, self).__init__(parent)

    def setEditorData(self, editor, index):
        if type(editor) == QtGui.QCheckBox:
            checkState = int(index.data())
            editor.setChecked(checkState)

            return

        return super(MyItemDelegate, self).setEditorData(editor, index)

    def setModelData(self, editor, model, index):
        if type(editor) == QtGui.QCheckBox:
            checkState = editor.isChecked()
            model.setData(index, str(int(checkState)))       

            return

        return super(MyItemDelegate, self).setModelData(editor, model, index)

class MyWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)

        self.labelRecord = QtGui.QLabel(self)

        self.pushButtonNext = QtGui.QPushButton(self)
        self.pushButtonNext.setText("Next!")
        self.pushButtonNext.clicked.connect(self.on_pushButtonNext_clicked)

        self.pushButtonPrevious = QtGui.QPushButton(self)
        self.pushButtonPrevious.setText("Previous!")
        self.pushButtonPrevious.clicked.connect(self.on_pushButtonPrevious_clicked)

        self.spacerItem = QtGui.QSpacerItem(
            40, 20,
            QtGui.QSizePolicy.Expanding,
            QtGui.QSizePolicy.Minimum
        )

        self.layoutHorizontal = QtGui.QHBoxLayout()
        self.layoutHorizontal.addItem(self.spacerItem)
        self.layoutHorizontal.addWidget(self.pushButtonPrevious)
        self.layoutHorizontal.addWidget(self.pushButtonNext)

        self.labelProperty = QtGui.QLabel(self)
        self.labelProperty.setText("Property")

        self.labelType = QtGui.QLabel(self)
        self.labelType.setText("Type")

        self.checkBoxBool = QtGui.QCheckBox(self)
        self.checkBoxBool.setText("Bool")

        self.lineEditProperty  = QtGui.QLineEdit(self)
        self.lineEditType      = QtGui.QLineEdit(self)
        self.standardItemModel = QtGui.QStandardItemModel(self)
        self.itemDelegate      = MyItemDelegate(self)

        for rowNumber in range(3):
            items = []
            for columnNumber in range(3):
                itemData = "row: {0} column {1}".format(
                    rowNumber,
                    columnNumber 
                )

                item = QtGui.QStandardItem(
                    itemData
                    if columnNumber != 2
                    else str(rowNumber - rowNumber/2*2)
                )
                items.append(item)

            self.standardItemModel.appendRow(items)

        self.tableView = QtGui.QTableView(self)
        self.tableView.setModel(self.standardItemModel)

        self.dataWidgetMapper = QtGui.QDataWidgetMapper(self)
        self.dataWidgetMapper.setModel(self.standardItemModel)
        self.dataWidgetMapper.addMapping(self.lineEditProperty, 0)
        self.dataWidgetMapper.addMapping(self.lineEditType, 1)
        self.dataWidgetMapper.addMapping(self.checkBoxBool, 2)
        self.dataWidgetMapper.setItemDelegate(self.itemDelegate)
        self.dataWidgetMapper.currentIndexChanged.connect(self.on_dataWidgetMapper_currentIndexChanged)
        self.dataWidgetMapper.toFirst()

        self.layoutGrid = QtGui.QGridLayout(self)
        self.layoutGrid.addWidget(self.tableView, 0, 0, 1, 2)
        self.layoutGrid.addWidget(self.labelRecord, 1, 0, 1, 2)
        self.layoutGrid.addWidget(self.labelProperty, 2, 0, 1, 1)
        self.layoutGrid.addWidget(self.lineEditProperty, 2, 1, 1, 1)
        self.layoutGrid.addWidget(self.labelType, 3, 0, 1, 1)
        self.layoutGrid.addWidget(self.lineEditType, 3, 1, 1, 1)
        self.layoutGrid.addWidget(self.checkBoxBool, 4, 1, 1, 1)
        self.layoutGrid.addLayout(self.layoutHorizontal, 5, 0, 1, 2)

    @QtCore.pyqtSlot(int)
    def on_dataWidgetMapper_currentIndexChanged(self, index):
        self.labelRecord.setText("<b>Record {0}</b>".format(index))
        self.pushButtonPrevious.setDisabled(index == 0)
        self.pushButtonNext.setDisabled(index == self.standardItemModel.rowCount() - 1)

    @QtCore.pyqtSlot()
    def on_pushButtonNext_clicked(self):
        self.dataWidgetMapper.toNext()

    @QtCore.pyqtSlot()
    def on_pushButtonPrevious_clicked(self):
        self.dataWidgetMapper.toPrevious()

#---------
# MAIN
#---------
if __name__ == "__main__":    
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName('MyWindow')

    main = MyWindow()
    main.setGeometry(0, 0, 333, 333)
    main.show()

    sys.exit(app.exec_())

这是一个很好的小部件映射器示例,我一直想研究这个。但似乎这将一个不断变化的数据集映射到静态的输入小部件集合中。有没有办法让代理创建多个映射器实例,以便我可以同时显示几个相同的小部件组? - horriblyUnpythonic
你可以为一个属性/类型组合创建自定义窗口小部件,然后创建一个列表,并在每行的代理中使用你的自定义窗口小部件。 - Goswin von Brederlow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接