我正在使用QSqlTableModel在QTableView中显示来自SQLite数据库的数据。让用户编辑此数据可以正常工作。但是,对于某些列,我想使用QComboboxes代替自由文本单元格来限制可能的答案列表。
我找到了this SO answer,并试图在我的模型/视图设置中实现它,但是我遇到了问题(因此是后续工作)。
这是一个完整的迷你示例:
#!/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)数据奇怪地出现在模型中(将第一列更改为“ VW”,“ Honda” ','Honda'产生('1','VW','1'在模型中)。我认为这是因为代码在委托人的setModelData中使用editor.currentIndex(),但是我还没有找到一种方法代替使用编辑器的内容。如何使代码将用户的选择正确地报告给模型?(如何在第一次单击时进行此操作,而无需单击两次?)>
任何帮助,我们将不胜感激。 (我已经阅读了documentation on QAbstractItemDelegate,但我认为它没有什么特别的帮助。)
答案 0 :(得分:1)
借助Rapid GUI Programming with Python and Qt这本书找到了解决方案:
createEditor
和setEditorData
不能按我预期的方式工作(我被误导了,因为示例代码看起来像是在使用文本内容,而是在处理索引号)。相反,它们应如下所示:
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())
我希望这可以帮助某人。