不能在QML TableView中显示来自QSqlQueryModel数据(Can't di

2019-10-20 21:08发布

I'm trying to display data from a MySQL database in a table with the help of TableViewcomponent of QML.

Initially I tried making a QSqlQueryModel object from a QSqlQuery object and pass it to QML context as a property. But I came to know from Qt documentation that I must implement roleNames() to supply column to role mapping to TableView, so I subclassed QSqlQueryModel like so

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()

and my QML is

import QtQuick 2.2
import QtQuick.Controls 1.1

TableView {
    width: 200
    height: 300
    model: tabmodel
}

but it's showing nothing, just a blank window

I can see my QSqlQuery is working as I can print data from database using value(n) method from that query. I've also checked with making rolenames() member function, but the end result is same.

def roleNames(self):
    roles = {
        Qt.UserRole + 1 : "id",
        Qt.UserRole + 2 : "name"
    }
    return roles

Update:

QSqlQueryModel works with widget classes, I've tested it with QTableView widget. But I need to make it work with 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()

Can anyone please help me to resolve this issue? Thanks in advance.

Answer 1:

好吧,您的评论提醒我,你确实需要重写data()的QML模型的缘故。 为什么? 由于QML的模型调用data()与ROLENAME给出的角色()。 它不调用data()Qt::DisplayRole像QWidget的世界。 此外,您需要定义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)

添加TableViewColumnTableView 。 请记住,角色是区分大小写的。 他们必须完全用什么角色名()返回匹配:

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插槽。 我们不叫角色名()在这里,因为我不知道如何使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]
        }
    }

}


文章来源: Can't display data from QSqlQueryModel in a QML TableView