在闲逛一些带有C ++答案的帖子之后,这些帖子不适合我的问题,而且比解释我试图在这里提出的问题更令人困惑。
我正在尝试对QSqlTableModel
进行子类化,因为我需要一些带有复选框的布尔列。完整的工作程序是:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
import sys
class ImportFilter (QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
print("Welcome to StandardDialog")
# Load the Window
#self.ui = uic.loadUi("ImportFilter.ui",self)
#self.ui.setModal(True)
self.buttonBox = QDialogButtonBox()
self.tableView_typeOfValues = QTableView()
layout = QVBoxLayout()
layout.addWidget(self.buttonBox)
layout.addWidget(self.tableView_typeOfValues)
self.setLayout(layout)
# Init Environmment
self.db = createConnection()
# create Models
self.setupModel()
#setup Views
self.setupView()
# connect Signals
self.buttonBox.clicked.connect(self.pushButton_Box_clicked)
self.show()
print("<- initUI")
def setupView(self):
print("-> setupView")
self.tableView_typeOfValues.setModel(self.tableView_typeOfValues_Model)
self.tableView_typeOfValues.setColumnWidth(0,10)
self.tableView_typeOfValues.setColumnWidth(1,130)
self.tableView_typeOfValues.setColumnWidth(2,130)
self.tableView_typeOfValues.setColumnWidth(3,60)
self.tableView_typeOfValues.setColumnWidth(4,60)
self.tableView_typeOfValues.setColumnWidth(5,60)
self.tableView_typeOfValues.setColumnWidth(6,60)
self.tableView_typeOfValues.hideColumn(0)
self.tableView_typeOfValues.hideColumn(3)
print("<- setupView")
def setupModel(self):
print("-> setupModel")
# own model
self.tableView_typeOfValues_Model = ImportSqlTableModel()
print(" tables:", self.db.tables())
print(' Before .setTable("typeOfValue") and select()')
self.tableView_typeOfValues_Model.info()
self.tableView_typeOfValues_Model.setTable("typeOfValue")
self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.tableView_typeOfValues_Model.select()
print(' After .setTable("typeOfValue") and select()')
self.tableView_typeOfValues_Model.info()
self.headerData()
print(" Table:",self.tableView_typeOfValues_Model.tableName())
print(" count:",self.tableView_typeOfValues_Model.rowCount())
self.tableView_typeOfValues_Model.info()
print("<- setupModel")
def setupModelQRY(self):
print("-> setupModel with Query")
# works so far
#self.tableView_typeOfValues_Model = QSqlTableModel() # edit but no checkboxes
self.tableView_typeOfValues_Model = ImportSqlTableModel(self.db) # no edit
# SET query
qry = QSqlQuery(self.db)
sql = "SELECT ID, name, unit, source, Import, ImportIfZero, visible FROM typeOfValue"
qry.prepare(sql)
qry.exec_(sql)
self.tableView_typeOfValues_Model.setQuery(qry)
self.tableView_typeOfValues_Model.select()
print(" Filter:",self.tableView_typeOfValues_Model.filter())
print(" SELECT:", self.tableView_typeOfValues_Model.selectStatement())
self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)
print("<- setupModel")
def headerData(self):
print("-> headerData")
self.tableView_typeOfValues_Model.setHeaderData(0,Qt.Horizontal, "ID")
self.tableView_typeOfValues_Model.setHeaderData(1,Qt.Horizontal, "name")
self.tableView_typeOfValues_Model.setHeaderData(2,Qt.Horizontal, "unit")
self.tableView_typeOfValues_Model.setHeaderData(3,Qt.Horizontal, "source")
self.tableView_typeOfValues_Model.setHeaderData(4,Qt.Horizontal, "Import")
self.tableView_typeOfValues_Model.setHeaderData(5,Qt.Horizontal, "ImportIfZero")
self.tableView_typeOfValues_Model.setHeaderData(6,Qt.Horizontal, "visible")
print("<- headerData")
###################################################################################################
# functions
###################################################################################################
def pushButton_Box_clicked(self,signal):
print("okButtonClicked")
print("buttonBox_clicked",signal)
self.tableView_typeOfValues_Model.submitAll()
self.exitcode = "ok, but not implemented"
sys.exit()
def returnCode(self):
return self.exitcode
#######################################################################################################################
# C L A S S
#######################################################################################################################
class ImportSqlTableModel(QSqlTableModel):
def __init__(self):
super(ImportSqlTableModel, self).__init__()
print("-> ImportSqlTableModel.__init__:")
self.booleanSet =[4,5,6]
self.readOnlySet = [1]
print(" Inside:")
self.info()
print("<- ImportSqlTableModel.__init__:")
def info(self):
print("-> info")
print(" ImportSqlTableModel tables inside :", self.database().tables())
print(" ImportSqlTableModel self.db :", self.database())
print(" ImportSqlTableModel self.Table :", self.tableName())
print(" ImportSqlTableModel self.rowCount :", self.rowCount())
print(" ImportSqlTableModel self.lastEror :", self.lastError().text())
print("<- info")
def columnCount(self, index):
count = QSqlTableModel.columnCount(self, index)
return count
def dataChanged(self, QModelIndex, QModelIndex_1, Iterable, p_int=None, *args, **kwargs):
print("-> Datachanged")
def data(self, index, role=Qt.DisplayRole):
print("-> ImportSqlModel.data",index, role)
print(" 1row :", index.row())
print(" col :", index.column())
print(" data :", self.record().fieldName(index.column()))
value = super(ImportSqlTableModel, self).data(index)
print(" value2:",value)
if index.column() in self.booleanSet:
if role == Qt.CheckStateRole:
if value == 2:
return QVariant(Qt.Unchecked)
else:
return QVariant(Qt.Checked)
else:
QSqlTableModel.data(self, index, role)
else:
return QSqlTableModel.data(self, index, role)
def setData(self, index, value, role=Qt.EditRole):
# works with changing value, but not saving
print("-> ImportSqlModel.setData",index,value,role)
print(" value:", value)
if not index.isValid():
return False
if role == Qt.EditRole:
print(" = Qt.Editrole")
QVariant(value)
print(" Update table")
self.select()
if index.column() in self.booleanSet and role == Qt.CheckStateRole:
print(" checkbox changed!")
if value == Qt.Checked:
print(" Qt.Checked")
return QSqlTableModel.setData(self, index, 2 , Qt.EditRole)
else:
print(" not Qt.Checked")
return QSqlTableModel.setData(self, index, 0 , Qt.EditRole)
else:
return QSqlTableModel.setData(self, index, value, role)
def flags(self, index):
print("-> ImportSqlModel.flags")
print(" index.isValid()",index.isValid())
if not index.isValid():
return Qt.ItemIsEnabled
if index.column() in self.booleanSet:
return Qt.ItemIsUserCheckable | Qt.ItemIsEnabled # | Qt.ItemIsSelectable | Qt.ItemIsEditable
elif index.column() in self.readOnlySet:
return Qt.ItemIsSelectable | Qt.ItemIsEnabled
else:
return QSqlTableModel.flags(self, index)
print("<- ImportSqlModel.flags")
#######################################################################################################################
# D E M O F U N C T I O N
#######################################################################################################################
def createConnection():
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('memory')
if not db.open():
QMessageBox.critical(None, qApp.tr("Cannot open database"),
qApp.tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information "
"how to build it.\n\n"
"Click Cancel to exit."),
QMessageBox.Cancel)
return False
query = QSqlQuery()
query.exec_("CREATE TABLE `typeOfValue` (`ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "\
"`name` TEXT NOT NULL, `unit` TEXT NOT NULL,`source` TEXT,`import` INTEGER,`importIfZero` INTEGER,"\
"`visible` INTEGER);")
query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
'("Sound", "dB", "live", 0,0,2)')
query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
'("Flow", "m/min", "live", 0,2,2)')
query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
'("Vibration", "mm/s", "live", 2,2,2)')
query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
'("Voltage", "V", "live", 0,0,0)')
query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
'("Ampere", "A", "live", 2,0,2)')
return db
#######################################################################################################################
# M A I N
#######################################################################################################################
if __name__ == '__main__':
createConnection()
app = QApplication(sys.argv)
prog = ImportFilter()
prog.show()
sys.exit(app.exec_())
我正在运行的问题是,当我使用查询来填充表时,我能够查看该表:
def setupModel(self):
print("-> setupModel")
# SET query
qry = QSqlQuery(self.gVar.db)
sql = "SELECT ID, name, unit, source, Import, ImportIfZero, visible FROM typeOfValue"
qry.prepare(sql)
qry.exec_(sql)
self.tableView_typeOfValues_Model.setQuery(qry)
但是我发现了错误,那就是导致了只读表。手册中描述了不应执行的操作:请参见here
所以我改为
.setTable("typeOfValue")
#=表名 self.tableView_typeOfValues_Model = ImportSqlTableModel(self.gVar.db)
self.tableView_typeOfValues_Model.setTable("typeOfValue")
self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.tableView_typeOfValues_Model.select()
但是现在我有一个空视图,如果我调用
self.lastError().text()
,我会得到一条消息,因为self.database().tables()
(在模型内部被调用)带来了一个空列表,所以找不到该表。对我而言,这意味着数据库未正确初始化,但是self.database()
带来了结果为0x042C4D30处的PyQt5.QtSql.QSqlDatabase对象。
请,有人可以给我提示纠正QSqlTableModel的子类化。谢谢!
最佳答案
该问题是由未为布尔类型列启用的Qt.ItemIsEditable标志引起的,在指令中这是必需的:
if index.column() in self.booleanSet and role == Qt.CheckStateRole:
print(" checkbox changed!")
if value == Qt.Checked:
print(" Qt.Checked")
return QSqlTableModel.setData(self, index, 2 , Qt.EditRole)
else:
print(" not Qt.Checked")
return QSqlTableModel.setData(self, index, 0 , Qt.EditRole)
因为它会验证该字段可以编辑。
因此解决方案是启用此标志,但为避免您可以写一些文本,我们将通过委托禁用编辑器:
class ReadOnlyDelegate(QItemDelegate):
def createEditor(self, parent, option, index):
lb = QLabel(parent)
return lb
完整的例子:
import sys
from PyQt5.QtCore import QVariant, Qt
from PyQt5.QtSql import QSqlTableModel, QSqlDatabase
from PyQt5.QtWidgets import QApplication, QTableView, QLabel, QItemDelegate
class ImportSqlTableModel(QSqlTableModel):
def __init__(self, *args, **kwargs):
super(ImportSqlTableModel, self).__init__(*args, **kwargs)
self.booleanSet = [4, 5, 6] # column with checkboxes
self.readOnlySet = [1] # columns which must not be changed
self.setTable("typeOfValue")
self.setEditStrategy(QSqlTableModel.OnFieldChange)
self.select()
def data(self, index, role=Qt.DisplayRole):
value = super(ImportSqlTableModel, self).data(index)
if index.column() in self.booleanSet:
if role == Qt.CheckStateRole:
return Qt.Unchecked if value == 2 else Qt.Checked
else:
return QVariant()
return QSqlTableModel.data(self, index, role)
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid():
return False
if index.column() in self.booleanSet:
if role == Qt.CheckStateRole:
val = 2 if value == Qt.Unchecked else 0
return QSqlTableModel.setData(self, index, val, Qt.EditRole)
else:
return False
else:
return QSqlTableModel.setData(self, index, value, role)
def flags(self, index):
if not index.isValid():
return Qt.NoItemFlags
if index.column() in self.booleanSet:
return Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsEditable
elif index.column() in self.readOnlySet:
return Qt.ItemIsSelectable | Qt.ItemIsEnabled
else:
return QSqlTableModel.flags(self, index)
class ReadOnlyDelegate(QItemDelegate):
def createEditor(self, parent, option, index):
lb = QLabel(parent)
return lb
if __name__ == '__main__':
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("/path/of/your_database.db")
if not db.open():
sys.exit(-1)
model = ImportSqlTableModel()
w = QTableView()
w.setModel(model)
for col in model.booleanSet:
w.setItemDelegateForColumn(col, ReadOnlyDelegate(w))
w.show()
sys.exit(app.exec_())