如何在QTableView中恢复QComboBox委托的索引?

时间:2015-07-12 11:07:51

标签: python qt model pyqt qcombobox

有一个QTableView(),其中一个列中填充了QComboBox个es。 问题是如何根据从词典中获取的数据选择QTableView()中的组合框中的项目

我发现我应该应用self.combo.setCurrentIndex(self.combo.findText( status_str)),但无法理解如何在status_str中获取变量comboBox或将代码放在应用它的位置。 另外,我无法理解双击后make 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_())

2 个答案:

答案 0 :(得分:3)

覆盖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)

以上是上述代码的最小工作示例!请注意,我已使用QVariant关闭对sip的支持,以便模型返回本机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_())

答案 1 :(得分:0)

为了不总是在单元格中看到组合框,您需要将QAbstracItemModel或类似的子类化,并将其设置为QTableView的模型,以便您可以覆盖其{{1}函数,描述每列中应显示的内容。

然后,若要在点击时显示组合框,并使其正确显示所选索引,我建议您查看QStyledItemDelegate

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

  1. 子类data()并在该子类中将QStyledItemDelegate作为成员。

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

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

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