PyQt - QCombobox in QTableview



我正在使用QSqlTableModel在QTableView中显示SQLite数据库的数据。让用户编辑此数据工作正常。但是,对于某些列,我想使用 QCombobox 而不是自由文本单元格来限制可能答案的列表。

我已经找到了这个 SO 答案,并正在尝试在我的模型/视图设置上实现它,但我遇到了问题(所以这是一个后续(。

下面是一个完整的迷你示例:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5 import QtSql
from PyQt5.QtWidgets import (QWidget, QTableView, QApplication, QHBoxLayout,
QItemDelegate, QComboBox)
from PyQt5.QtCore import pyqtSlot
import sys
class ComboDelegate(QItemDelegate):
"""
A delegate that places a fully functioning QComboBox in every
cell of the column to which it's applied
source: https://gist.github.com/Riateche/5984815
"""
def __init__(self, parent, items):
self.items = items
QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
combo = QComboBox(parent)
li = []
for item in self.items:
li.append(item)
combo.addItems(li)
combo.currentIndexChanged.connect(self.currentIndexChanged)
return combo
def setEditorData(self, editor, index):
editor.blockSignals(True)
#         editor.setCurrentIndex(int(index.model().data(index))) #from original code
editor.setCurrentIndex(index.row()) # replacement
editor.blockSignals(False)
def setModelData(self, editor, model, index):
model.setData(index, editor.currentIndex())
@pyqtSlot()
def currentIndexChanged(self):
self.commitData.emit(self.sender())

class Example(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 150)
self.createConnection()
self.fillTable() # comment out to skip re-creating the SQL table
self.createModel()
self.initUI()
def createConnection(self):
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("test.db")
if not self.db.open():
print("Cannot establish a database connection")
return False
def fillTable(self):
self.db.transaction()
q = QtSql.QSqlQuery()
q.exec_("DROP TABLE IF EXISTS Cars;")
q.exec_("CREATE TABLE Cars (Company TEXT, Model TEXT, Year NUMBER);")
q.exec_("INSERT INTO Cars VALUES ('Honda', 'Civic', 2009);")
q.exec_("INSERT INTO Cars VALUES ('VW', 'Golf', 2013);")
q.exec_("INSERT INTO Cars VALUES ('VW', 'Polo', 1999);")
self.db.commit()
def createModel(self):
self.model = QtSql.QSqlTableModel()
self.model.setTable("Cars")
self.model.select()
def initUI(self):
layout = QHBoxLayout()
self.setLayout(layout)
view = QTableView()
layout.addWidget(view)
view.setModel(self.model)
view.setItemDelegateForColumn(0, ComboDelegate(self, ["VW", "Honda"]))
for row in range(0, self.model.rowCount()):
view.openPersistentEditor(self.model.index(row, 0))
def closeEvent(self, e):
for row in range(self.model.rowCount()):
print("row {}: company = {}".format(row, self.model.data(self.model.index(row, 0))))
if (self.db.open()):
self.db.close()

def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())

if __name__ == '__main__':
main()

在这种情况下,我想在"公司"列上使用QCombobox。它应该一直显示,所以我调用openPersistentEditor。

问题 1:默认值我希望这在未编辑时显示未编辑字段的内容(即模型中列出的公司(,但它显然显示了组合框选择的第 i 个元素。如何使每个组合框默认显示此字段的模型实际内容?

问题 2:编辑注释掉"self.fill_table(("时,可以检查编辑是否到达 SQL 数据库。我希望在下拉列表中选择任何字段都会替换原始值。但是 (a( 我必须做出两次选择(第一次,单元格中显示的值保持不变(,并且 (b( 数据奇怪地出现在模型中(将第一列更改为"大众"、"本田"、"本田"结果(模型中的"1"、"大众"、"1"(。我认为这是因为代码在委托的 setModelData 中使用了 editor.currentIndex((,但我还没有找到使用编辑器内容的方法。如何使代码将用户的选择正确报告回模型?(我如何在第一次点击时完成这项工作,而不是需要 2 次点击?

任何帮助非常感谢。(我已经阅读了QAbstractItemDelegate的文档,但我发现它不是特别有用。

在《Rapid GUI Programming with Python and Qt》一书的帮助下找到了解决方案:

createEditorsetEditorData没有按我的预期工作(我被误导了,因为示例代码看起来像是在使用文本内容,而是在处理索引号(。相反,它们应如下所示:

def setEditorData(self, editor, index):
editor.blockSignals(True)
text = index.model().data(index, Qt.DisplayRole)
try:
i = self.items.index(text)
except ValueError:
i = 0
editor.setCurrentIndex(i)
editor.blockSignals(False)
def setModelData(self, editor, model, index):
model.setData(index, editor.currentText())

我希望这对某人有所帮助。

最新更新