python - PySide2 SQLITE 表视图
问题描述
在尝试QSQLITE
在 QML 中显示表中的数据时,TableView
我偶然发现了这个答案并试图跟进它。我理解重新实施的必要性,data()
但是roleNames()
当涉及到QVariant
PySide2 中不存在的问题时,我遇到了问题。我明白了NameError: name 'QVariant' is not defined
。我已经测试了从数据库读取数据,它的工作。是否有任何数据类型可以代替QVariant
PySide2 使用?我的计划是拥有来自不同表的多个数据源。这个例子使用setContextProperty
,在这种情况下使用是更好的做法qmlRegisterType
吗?
文件夹结构
├── ViewModel
│ └── QCond.py
├── Qml
│ └── Modellist.qml
└── qmlengine.py
qmlengine.py
import os
import sys
from PySide2.QtCore import QUrl, QStringListModel, QCoreApplication, Qt
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide2.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
from ViewModel.QCond import *
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("C:\\Users\\terao\\Documents\\ctmd\\CatData.db")
db.open()
qry = QSqlQuery()
qry=db.exec_("SELECT tip,s FROM uzad")
tabmodel = QtCond()
tabmodel.setQuery(qry)
engine.rootContext().setContextProperty("tabmodel", tabmodel)
engine.load(QUrl.fromLocalFile('Qml/Modellist.qml'))
if not engine.rootObjects():
sys.exit(-2)
sys.exit(app.exec_())
QCond.py
import sys
from PySide2 import QtCore, QtGui, QtQml
from PySide2.QtCore import QObject, Qt,Signal, Slot, QUrl, QStringListModel, QCoreApplication
import sqlite3
from PySide2.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
class QtCond(QSqlQueryModel):
def __init__(self):
super(QtCond, self).__init__()
def roleNames(self):
roles = {
Qt.UserRole + 1 : 'tip',
Qt.UserRole + 2 : 's'
}
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)
@QtCore.Slot(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(str(value))
return QVariant(list)
模型列表.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5
TableView {
width: 1000
height: 1000
model: tabmodel
TableViewColumn {
role: "tip" // case-sensitive, must match a role returned by roleNames()
}
TableViewColumn {
role: "s"
}
}
任何帮助表示赞赏。提前致谢。
解决方案
在您的情况下,roleNameArray 返回一个列表,正如我在这个答案中指出的那样,您必须使用“QVariantList”。另一方面,我通过根据我的旧答案概括示例来改进示例:(1),(2),考虑到解决方案是:
├── db
│ └── CatData.db
├── qml
│ └── Modellist.qml
├── qmlengine.py
└── ViewModel
└── model.py
视图模型/模型.py
from PySide2 import QtCore, QtSql
class SqlQueryModel(QtSql.QSqlQueryModel):
def data(self, index, role=QtCore.Qt.DisplayRole):
value = None
if index.isValid():
if role < QtCore.Qt.UserRole:
value = super(SqlQueryModel, self).data(index, role)
else:
columnIdx = role - QtCore.Qt.UserRole - 1
modelIndex = self.index(index.row(), columnIdx)
value = super(SqlQueryModel, self).data(
modelIndex, QtCore.Qt.DisplayRole
)
return value
def roleNames(self):
roles = dict()
for i in range(self.record().count()):
roles[QtCore.Qt.UserRole + i + 1] = self.record().fieldName(i).encode()
return roles
@QtCore.Slot(result="QVariantList")
def roleNameArray(self):
names = []
for i in range(self.record().count()):
names.append(self.record().fieldName(i))
return names
qml/模型列表.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5
ApplicationWindow{
width: 1000
height: 1000
visible: true
TableView {
anchors.fill: parent
model: tabmodel
/*TableViewColumn {
role: "tip"
}
TableViewColumn {
role: "s"
}*/
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]
}
}
}
}
qmlengine.py
import os
import sys
from PySide2 import QtCore, QtGui, QtSql, QtQml
from ViewModel.model import SqlQueryModel
def create_connection(path):
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(path)
if not db.open():
print('''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.''')
return False
return True
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
app = QtGui.QGuiApplication(sys.argv)
engine = QtQml.QQmlApplicationEngine()
db_path = os.path.join(current_dir, "db", "CatData.db")
if not create_connection(db_path):
sys.exit(-1)
tabmodel = SqlQueryModel()
tabmodel.setQuery("SELECT tip,s FROM uzad")
engine.rootContext().setContextProperty("tabmodel", tabmodel)
qml_path = os.path.join("qml", "Modellist.qml")
engine.load(QtCore.QUrl.fromLocalFile(qml_path))
if not engine.rootObjects():
sys.exit(-2)
sys.exit(app.exec_())
输出:
qmlRegisterType 的目标是通过抽象起源和实现在 QML 中注册 Python/C++ 类型。在您的情况下,如果您想注册它,最好是查询是一个 qproperty,以便可以从 QML 访问它:
视图模型/模型.py
from PySide2 import QtCore, QtSql
class SqlQueryModel(QtSql.QSqlQueryModel):
queryStrChanged = QtCore.Signal(str)
def get_query_str(self):
return self.query().lastQuery()
def set_query_str(self, query):
if self.get_query_str() == query:
return
self.setQuery(query)
self.queryStrChanged.emit(query)
query_str = QtCore.Property(
str, fget=get_query_str, fset=set_query_str, notify=queryStrChanged
)
def data(self, index, role=QtCore.Qt.DisplayRole):
value = None
if index.isValid():
if role < QtCore.Qt.UserRole:
value = super(SqlQueryModel, self).data(index, role)
else:
columnIdx = role - QtCore.Qt.UserRole - 1
modelIndex = self.index(index.row(), columnIdx)
value = super(SqlQueryModel, self).data(
modelIndex, QtCore.Qt.DisplayRole
)
return value
def roleNames(self):
roles = dict()
for i in range(self.record().count()):
roles[QtCore.Qt.UserRole + i + 1] = self.record().fieldName(i).encode()
return roles
@QtCore.Slot(result="QVariantList")
def roleNameArray(self):
names = []
for i in range(self.record().count()):
names.append(self.record().fieldName(i))
return names
qml/模型列表.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5
import mycomponents 1.0
ApplicationWindow{
width: 1000
height: 1000
visible: true
SqlQueryModel{
id: tabmodel
query_str: "SELECT tip,s FROM uzad"
}
TableView {
anchors.fill: parent
model: tabmodel
/*TableViewColumn {
role: "tip"
}
TableViewColumn {
role: "s"
}*/
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]
}
}
}
}
qmlengine.py
import os
import sys
from PySide2 import QtCore, QtGui, QtSql, QtQml
from ViewModel.model import SqlQueryModel
def create_connection(path):
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(path)
if not db.open():
print('''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.''')
return False
return True
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
QtQml.qmlRegisterType(SqlQueryModel, "mycomponents", 1, 0, "SqlQueryModel")
app = QtGui.QGuiApplication(sys.argv)
engine = QtQml.QQmlApplicationEngine()
db_path = os.path.join(current_dir, "db", "CatData.db")
if not create_connection(db_path):
sys.exit(-1)
qml_path = os.path.join("qml", "Modellist.qml")
engine.load(QtCore.QUrl.fromLocalFile(qml_path))
if not engine.rootObjects():
sys.exit(-2)
sys.exit(app.exec_())
推荐阅读
- javascript - 反应子回调绑定 this 而不覆盖原始 this
- java - AWS Api Gateway - Java SDK 生成“生成 SDK 时发生内部错误”
- pycharm - 无法添加自定义后缀完成模板
- python - tf.estimator.LinearClassifier 输出权重解释
- c - 不理解 printf() 的奇怪行为
- imagick - Imagick php 无法正确打印印地语 utf8 字符
- api - Akaunting API - 创建、更新和删除发票
- kotlin - GSON 可能出现故障?还是编码不好?
- node.js - 使用 mongoose 更新对象数组中的值
- wordpress - 在将网站链接复制并粘贴到社交媒体时从首页删除“主页标题”