【问题标题】:Custom abstract widgets with PyQt使用 PyQt 自定义抽象小部件
【发布时间】:2013-08-26 20:29:58
【问题描述】:

我现在已经在 PyQt 中做了几个项目,并且我越来越熟悉 Qt 采用的模型/视图学派。我已经将它用于列表和表格视图之类的东西,它们背后有一个自定义模型来显示和操作数据。我使用委托来编辑每个单元格/行中的基础信息。

如何在 Qt 中抽象出这个模型/视图架构以消除对表格/列表的需求?直接切到编辑委托。

视觉上说,可以这样:

在一行中的编辑触发器会像这样打开一个委托

我想换一个看起来更像这样的东西

其中与thing1、thing2 和另一个事物对应的对象不是静态的,可以在多个视图之间共享。很像将 QAbstractModel 与 QTableView 一起使用。

【问题讨论】:

    标签: pyqt model-view


    【解决方案1】:

    您可以使用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_())
    

    【讨论】:

    • 这是一个很好的小部件映射器示例,我一直想研究这些。但这似乎是将一组变化的数据映射到一组静态的输入小部件。有什么方法可以让委托创建映射器的多个实例,以便我可以一次显示多个相同的小部件组?
    • 您可以为一个事物/属性/类型三元组制作一个自定义小部件,然后您制作一个列表并在每一行的委托中使用您的自定义小部件。
    猜你喜欢
    • 2015-11-19
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    • 2018-04-20
    • 1970-01-01
    • 2014-02-10
    • 1970-01-01
    相关资源
    最近更新 更多