无法在QML TableView中显示QSqlQueryModel的数据
我正在尝试使用QML中的TableView
组件来显示来自MySQL数据库的数据。
最开始,我试着从QSqlQuery
对象创建一个QSqlQueryModel
对象,并把它作为属性传递给QML上下文。但我从Qt文档了解到,我必须实现roleNames()
方法,以便为TableView
提供列到角色的映射,所以我像这样对QSqlQueryModel
进行了子类化
import sys
from PyQt5.QtCore import QUrl, Qt
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
class QtTabModel(QSqlQueryModel):
def __init__(self):
super(QtTabModel, self).__init__()
@staticmethod
def roleNames():
roles = {
Qt.UserRole + 1 : "id",
Qt.UserRole + 2 : "name"
}
return roles
app = QGuiApplication(sys.argv)
view = QQuickView()
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName("localhost")
db.setDatabaseName("qtdb")
db.setUserName("abc")
db.setPassword("xyz")
qry = QSqlQuery()
if db.open():
qry = db.exec("SELECT id, name FROM qttab")
tabmodel = QtTabModel()
tabmodel.setQuery(qry)
ctx = view.rootContext()
ctx.setContextProperty("tabmodel", tabmodel)
view.setSource(QUrl.fromLocalFile("sqltabletest.qml"))
view.show()
app.exec()
我的QML代码是
import QtQuick 2.2
import QtQuick.Controls 1.1
TableView {
width: 200
height: 300
model: tabmodel
}
但是它什么都不显示,只是一个空白窗口
我可以看到我的QSqlQuery
是有效的,因为我可以使用value(n)
方法从查询中打印数据库的数据。我也检查了rolenames()
这个成员函数,但最终结果还是一样。
def roleNames(self):
roles = {
Qt.UserRole + 1 : "id",
Qt.UserRole + 2 : "name"
}
return roles
更新:
QSqlQueryModel
可以与小部件类一起使用,我已经用QTableView
小部件测试过了。但我需要让它在QML中工作。
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QTableView
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName("localhost")
db.setDatabaseName("qtdb")
db.setUserName("abc")
db.setPassword("xyz")
qry = QSqlQuery()
if db.open():
qry = db.exec("SELECT id, name FROM qttab")
tabmodel = QSqlQueryModel()
tabmodel.setQuery(qry)
tabmodel.setHeaderData(0, Qt.Horizontal, "ID")
tabmodel.setHeaderData(1, Qt.Horizontal, "Name")
tabview = QTableView()
tabview.setModel(tabmodel)
tabview.show()
db.close()
app.exec()
有没有人能帮我解决这个问题?非常感谢。
1 个回答
好的,你的评论让我想起了,确实需要重新实现 data()
方法,以适应 QML 的模型。为什么呢?因为 QML 的模型会用 roleName()
提供的角色来调用 data()
。它不会像在 QWidget 中那样用 Qt::DisplayRole
来调用 data()
。而且,你需要用角色名称来定义 TableViewColumn
,否则模型就不会调用 data()
。下面是一个如何重新实现 data()
的例子:
import sys
from PyQt5.QtCore import QUrl, Qt, QVariant
from PyQt5.QtCore import QObject, pyqtSlot
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
class QtTabModel(QSqlQueryModel):
def __init__(self):
super(QtTabModel, self).__init__()
def roleNames(self):
roles = {
Qt.UserRole + 1 : 'id',
Qt.UserRole + 2 : 'name'
}
return roles
def data(self, index, role):
if role < Qt.UserRole:
# caller requests non-UserRole data, just pass to papa
return super(QtTabModel, self).data(index, role)
# caller requests UserRole data, convert role to column (role - Qt.UserRole -1) to return correct data
return super(QtTabModel, self).data(self.index(index.row(), role - Qt.UserRole -1), Qt.DisplayRole)
@pyqtSlot(result=QVariant) # don't know how to return a python array/list, so just use QVariant
def roleNameArray(self):
# This method is used to return a list that QML understands
list = []
# list = self.roleNames().items()
for key, value in self.roleNames().items():
list.append(value)
return QVariant(list)
把 TableViewColumn
添加到 TableView
中。要记住,角色是区分大小写的。它们必须和 roleNames()
返回的内容完全一致:
import QtQuick 2.2
import QtQuick.Controls 1.1
TableView {
width: 200
height: 300
model: tabmodel
TableViewColumn {
role: "id" // case-sensitive, must match a role returned by roleNames()
}
TableViewColumn {
role: "name"
}
}
这里有一种自动生成 TableViewColumn
的方法。它调用上面 Python 代码中定义的 roleNameArray
槽来获取角色名称列表。我们在这里不调用 roleNames()
,因为我不知道怎么让 QML 理解它返回的结果 :),所以我们必须把它转换成一个列表。最后,我们遍历这个列表,并调用 TableView.addColumn
来创建列:
TableView {
width: 200
height: 300
model: tabmodel
Component.onCompleted: {
var roles = model.roleNameArray()
for (var i=0; i<roles.length; i++) {
var column = addColumn( Qt.createQmlObject(
"import QtQuick.Controls 1.1; TableViewColumn {}",
this) )
column.role = roles[i]
column.title = roles[i]
}
}
}