如何在 QTableView 中恢复 QComboBox 委托的索引?
How to restore the index of a QComboBox delegate in a QTableView?
有一个QTableView()
,其中一列是QComboBox
。
问题是如何根据从字典
中获取的数据QTableView()
中的组合框select项
我知道我应该应用 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_())
为了不总是在单元格中看到组合框,您需要子class QAbstracItemModel
或类似的,并将其设置为您的QTableView
的模型,这样您可以覆盖其 data()
函数,该函数描述了每列中应显示的内容。
然后,要使组合框在点击时出现,并使其正确显示所选索引,我建议您看看QStyledItemDelegate
。
您最好自己阅读并了解详细信息,但这里有一个关于如何使用它的粗略概述:
Subclass QStyledItemDelegate
并且在那个 subclass 中有你的 QComboBox
作为成员。
将其 createEditor()
功能覆盖到 return 组合框。因此,当您将此委托设置为列的项目委托时,将显示组合框以供编辑。
Subclass QAbstractListModel
并将其设置为组合框的模型。它将保存您的组合框的条目,并确保始终显示正确的索引,而无需您搜索索引。
再次阅读如何正确完成这些步骤中的每一个,例如如何正确地子class 抽象模型。您可以在每个 class 文档的 "details" 部分找到所有信息。
重写 QItemDelegate.paint
不是创建委托的推荐方法。 QItemDelegate
具有诸如 createEditor
和 setEditorData
之类的方法,您应该改写这些方法。 Qt 会适当地调用这些方法。
在 createEditor
中,您应该创建自己的 comboBox
,然后 return。例如:
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
索引而不是文本),你可以 save/restore 数据到不同的角色(例如 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
的支持,因此模型 return 的原生 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
的问题。我有一个 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)
完整的工作示例:
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_())
有一个QTableView()
,其中一列是QComboBox
。
问题是如何根据从字典
QTableView()
中的组合框select项
我知道我应该应用 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_())
为了不总是在单元格中看到组合框,您需要子class QAbstracItemModel
或类似的,并将其设置为您的QTableView
的模型,这样您可以覆盖其 data()
函数,该函数描述了每列中应显示的内容。
然后,要使组合框在点击时出现,并使其正确显示所选索引,我建议您看看QStyledItemDelegate
。
您最好自己阅读并了解详细信息,但这里有一个关于如何使用它的粗略概述:
Subclass
QStyledItemDelegate
并且在那个 subclass 中有你的QComboBox
作为成员。将其
createEditor()
功能覆盖到 return 组合框。因此,当您将此委托设置为列的项目委托时,将显示组合框以供编辑。Subclass
QAbstractListModel
并将其设置为组合框的模型。它将保存您的组合框的条目,并确保始终显示正确的索引,而无需您搜索索引。
再次阅读如何正确完成这些步骤中的每一个,例如如何正确地子class 抽象模型。您可以在每个 class 文档的 "details" 部分找到所有信息。
重写 QItemDelegate.paint
不是创建委托的推荐方法。 QItemDelegate
具有诸如 createEditor
和 setEditorData
之类的方法,您应该改写这些方法。 Qt 会适当地调用这些方法。
在 createEditor
中,您应该创建自己的 comboBox
,然后 return。例如:
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
索引而不是文本),你可以 save/restore 数据到不同的角色(例如 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
的支持,因此模型 return 的原生 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
的问题。我有一个 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)
完整的工作示例:
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_())