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

Ser*_*ele 2 python qt model pyqt qcombobox

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

我知道我应该申请,self.combo.setCurrentIndex(self.combo.findText( status_str))但无法理解如何将该变量status_str放入comboBox或放置在代码中应用它的位置。我也无法理解 makecomboBox只有在双击后才会出现。如果没有双击单元格,它必须看起来像任何其他单元格。

代码示例:

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_())
Run Code Online (Sandbox Code Playgroud)

thr*_*les 5

重写QItemDelegate.paint不是创建委托的推荐方法。QItemDelegate有诸如createEditor和 之类的方法setEditorData,您应该重写这些方法。这些方法由 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
Run Code Online (Sandbox Code Playgroud)

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

def setEditorData(self, editor, index):
    value = index.model().data(index, Qt.EditRole)
    editor.setCurrentIndex(editor.findText(value))
Run Code Online (Sandbox Code Playgroud)

请注意,在此示例中,我依赖于的默认实现QItemDelegate.setModelData()将 的当前文本保存comboboxEditRole. 如果您想做一些更复杂的事情(例如保存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)
Run Code Online (Sandbox Code Playgroud)

这是上述代码的最小工作示例!请注意,我已关闭对QVariantusing 的支持,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_())
Run Code Online (Sandbox Code Playgroud)

编辑

我刚刚注意到您关于comboBox双击后自动显示的另一个问题。我有一个 hack 来做我以前用过的。它依赖于将视图传递给委托并将以下几行添加到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)
Run Code Online (Sandbox Code Playgroud)

完整的工作示例:

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_())
Run Code Online (Sandbox Code Playgroud)