无法在QML TableView中显示来自QSqlQueryModel的数据

时间:2014-09-06 12:01:31

标签: python mysql pyqt qml pyqt5

我试图在QML的TableView组件的帮助下在表中显示MySQL数据库中的数据。

最初我尝试从QSqlQueryModel对象创建一个QSqlQuery对象,并将其作为属性传递给QML上下文。但是我从Qt documentation开始知道我必须实现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
}

但它没有显示任何内容,只是一个空白窗口

blank window from Qt5 in Ubuntu 14.04

我可以看到我的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()

working Qt5 code

有人可以帮我解决这个问题吗?提前谢谢。

1 个答案:

答案 0 :(得分:4)

好的,您的评论提醒我,您确实需要为QML的模型重新实现data()。为什么?因为QML的模型使用roleName()给出的角色调用data()。它不像QWidget世界那样用data()调用Qt::DisplayRole。此外,您需要使用角色名称定义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]
        }
    }

}