【问题标题】:How to restore the index of a QComboBox delegate in a QTableView?如何在 QTableView 中恢复 QComboBox 委托的索引?
【发布时间】:2015-09-30 18:10:03
【问题描述】:

有一个QTableView(),它的一列用QComboBoxes 填充。 问题是如何根据字典中的数据选择组合框中QTableView()中的项目

我知道我应该应用self.combo.setCurrentIndex(self.combo.findText( status_str)),但不明白如何在comboBox 中获取该变量status_str 或将其放在代码中应用它的位置。 我也无法理解如何让comboBox 仅在双击后出现。如果单元格没有被双击,它必须看起来像任何其他单元格。

代码示例:

data = {"first":{"status":"closed"},"second":{"status":"expired"},"third":{ "status":"cancelled"}}
class ComboDelegate(QItemDelegate):
    def __init__(self, parent):
        QItemDelegate.__init__(self, parent)
    def paint(self, painter, option, index):
        self.combo = QComboBox(self.parent())
        li = []
        li.append("closed")
        li.append("expired")
        li.append("cancelled")
        li.append("waiting")
        self.combo.addItems(li)
        #self.combo.setCurrentIndex(self.combo.findText( status_str ))
        if not self.parent().indexWidget(index):
            self.parent().setIndexWidget(           index,          self.combo          )

class TableView(QTableView):
    def __init__(self, *args, **kwargs):
        QTableView.__init__(self, *args, **kwargs)
        self.setItemDelegateForColumn(1, ComboDelegate(self))

class MainFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        table = TableView(self)
        self.model = QStandardItemModel()
        table.setModel(self.model)
        MainWindow = QVBoxLayout()
        MainWindow.addWidget(table)
        self.setLayout(MainWindow)
        self.fillModel()

    def fillModel(self):
        for i in data:
            print i
            name_str = i
            status_str = data[i]["status"]
            name = QStandardItem(name_str)
            status = QStandardItem(status_str)
            items = [name, status]
            self.model.appendRow(items)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainFrame()
    main.show()
    main.move(app.desktop().screen().rect().center() -     main.rect().center())
    sys.exit(app.exec_())

【问题讨论】:

    标签: python qt model pyqt qcombobox


    【解决方案1】:

    重写QItemDelegate.paint 不是创建委托的推荐方法。 QItemDelegate 具有诸如 createEditorsetEditorData 之类的方法,您应该重写它们。这些方法被 Qt 适当地调用。

    createEditor 中,您应该创建您的comboBox,并返回它。例如:

    def createEditor(self, parent, option, index):
        editor = QComboBox(parent)
        li = []
        li.append("closed")
        li.append("expired")
        li.append("cancelled")
        li.append("waiting")
        editor.addItems(li)
        return editor
    

    setEditorData 中,您可以在模型中查询组合框的当前索引。这将被称为例如:

    def setEditorData(self, editor, index):
        value = index.model().data(index, Qt.EditRole)
        editor.setCurrentIndex(editor.findText(value))
    

    请注意,在此示例中,我依靠QItemDelegate.setModelData() 的默认实现将combobox 的当前文本保存到EditRole。如果您想做一些更复杂的事情(例如保存combobox 索引而不是文本),您可以将数据保存/恢复到不同的角色(例如Qt.UserRole),在这种情况下您可以修改获得在setEditorData 方法中的作用以及覆盖setModelData,如下所示:

    def setEditorData(self, editor, index):
        value = index.model().data(index, Qt.UserRole)
        editor.setCurrentIndex(int(value))
    
    def setModelData(self, editor, model, index):
        model.setData(index, editor.currentIndex(), Qt.UserRole)
    

    这是上述代码的最小工作示例!请注意,我使用sip 关闭了对QVariant 的支持,以便模型返回本机Python 类型。

    import sys
    import sip
    sip.setapi('QVariant', 2)
    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
    
    data = {"first":{"status":"closed"},"second":{"status":"expired"},"third":{ "status":"cancelled"}}
    
    class ComboDelegate(QItemDelegate):
    
        def createEditor(self, parent, option, index):
            editor = QComboBox(parent)
            li = []
            li.append("closed")
            li.append("expired")
            li.append("cancelled")
            li.append("waiting")
            editor.addItems(li)
            return editor
    
        def setEditorData(self, editor, index):
            value = index.model().data(index, Qt.EditRole)
            editor.setCurrentIndex(editor.findText(value))
    
    
    class Example(QMainWindow):
    
        def __init__(self):
            super(Example, self).__init__()
    
            self.tableview = QTableView()
            self.tableview.setItemDelegateForColumn(1, ComboDelegate())
    
            self.setCentralWidget(self.tableview)
    
            self.model = QStandardItemModel()
            self.tableview.setModel(self.model)
            self.fillModel()
    
            self.show()
    
        def fillModel(self):
            for i in data:
                name_str = i
                status_str = data[i]["status"]
                name = QStandardItem(name_str)
                status = QStandardItem(status_str)
                items = [name, status]
                self.model.appendRow(items)
    
    
    if __name__ == '__main__':    
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    

    编辑

    我刚刚注意到您关于双击后自动显示comboBox 的其他问题。我有一个我以前用过的技巧。它依赖于将视图传递给委托并将以下几行添加到 createEditor 方法:

            editor.activated.connect(lambda index, editor=editor: self._view.commitData(editor))
            editor.activated.connect(lambda index, editor=editor: self._view.closeEditor(editor,QAbstractItemDelegate.NoHint))
            QTimer.singleShot(10,editor.showPopup)
    

    完整的工作示例:

    import sys
    import sip
    sip.setapi('QVariant', 2)
    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
    
    data = {"first":{"status":"closed"},"second":{"status":"expired"},"third":{ "status":"cancelled"}}
    
    class ComboDelegate(QItemDelegate):
        def __init__(self, view):
            QItemDelegate.__init__(self)
            self._view = view
    
    
        def createEditor(self, parent, option, index):
            editor = QComboBox(parent)
            li = []
            li.append("closed")
            li.append("expired")
            li.append("cancelled")
            li.append("waiting")
            editor.addItems(li)
    
    
            editor.activated.connect(lambda index, editor=editor: self._view.commitData(editor))
            editor.activated.connect(lambda index, editor=editor: self._view.closeEditor(editor,QAbstractItemDelegate.NoHint))
            QTimer.singleShot(10,editor.showPopup)
    
            return editor
    
        def setEditorData(self, editor, index):
            value = index.model().data(index, Qt.EditRole)
            editor.setCurrentIndex(editor.findText(value))
    
    
    class Example(QMainWindow):
    
        def __init__(self):
            super(Example, self).__init__()
    
            self.tableview = QTableView()
            self.tableview.setItemDelegateForColumn(1, ComboDelegate(self.tableview))
    
            self.setCentralWidget(self.tableview)
    
            self.model = QStandardItemModel()
            self.tableview.setModel(self.model)
            self.fillModel()
    
            self.show()
    
        def fillModel(self):
            for i in data:
                name_str = i
                status_str = data[i]["status"]
                name = QStandardItem(name_str)
                status = QStandardItem(status_str)
                items = [name, status]
                self.model.appendRow(items)
    
    
    if __name__ == '__main__':    
        app = QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    

    【讨论】:

    • 非常感谢。这就是我试图找到的确切解决方案。
    【解决方案2】:

    为了不总是在单元格中看到组合框,您需要继承QAbstracItemModel 或类似的子类,并将其设置为QTableView 的模型,以便您可以覆盖其data() 函数,它描述每列应该显示什么。

    然后,要让组合框在点击时出现,并使其正确显示所选索引,我建议你看看QStyledItemDelegate

    最好自己阅读并弄清楚细节,但这里有一个关于如何使用它的粗略概述:

    1. 子类 QStyledItemDelegate 并在该子类中将您的 QComboBox 作为成员。

    2. 覆盖其createEditor() 函数以返回组合框。因此,当您将此委托设置为列的项目委托时,将显示组合框以供编辑。

    3. 子类 QAbstractListModel 并将其设置为组合框的模型。它将保存组合框的条目,并确保始终显示正确的索引,而无需搜索索引。

    再次,阅读如何正确完成每个步骤,例如如何正确子类化抽象模型。您可以在每个类文档的“详细信息”部分找到所有信息。

    【讨论】:

    • 没有必要继承QAbstractItemModel,因为他们已经在使用QStandardItemModel。您可以改用item.setData(data, role)
    • @three_pineapples 所以我尝试了status = QStandardItem() status.setData(status_str, Qt.EditRole) 它显示了组合框,并且状态列中的每个单元格都具有相同的选择状态,尽管status_str 的值是什么。您能否举例说明我该怎么做。我确实阅读了文档,但缺乏经验不允许我在没有示例的情况下将裸信息绑定在一起
    • @SergiiArtele 我会尽快找时间提供一个完整的例子。如果我忘记了,麻烦我!
    猜你喜欢
    • 2015-03-18
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多