PyQt5中QML调用Python函数赋值ListElement属性失败问题
问题:PyQt5中QML的ListElement无法调用Python函数获取值
我来帮你梳理这个问题的原因和解决方案:
问题重现
你在PyQt5中把Python的MyDB类暴露给QML后,在Text组件的property里调用myDB.getIncome()能正常拿到字符串,但把同样的调用放到ListElement的属性赋值时就失效了。相关代码如下:
Python代码(main.py)
import sys from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtSignal, pyqtProperty, QVariant from PyQt5.QtWidgets import QApplication from PyQt5.QtQuick import QQuickView class MyDB(QObject): def __init__(self): super().__init__() @pyqtSlot(result=str) def getIncome(self): return "testing income" if __name__ == '__main__': myApp = QApplication(sys.argv) appLabel = QQuickView() mydb = MyDB() appLabel.rootContext().setContextProperty("myDB", mydb) appLabel.setSource(QUrl('main.qml')) appLabel.show() myApp.exec_() sys.exit()
可正常运行的QML代码
import QtQuick 2.2 Rectangle { id: root width: 250; height: 450 color: "gray" Text { id: exp anchors.centerIn: parent color: 'dark red' horizontalAlignment: Text.AlignHCenter font.pixelSize: 18 property string value: myDB.getIncome() text: value } }
失效的QML代码
import QtQuick 2.0 Rectangle { id: root width: 250; height: 450 color: "white" ListModel { id: mainModel ListElement { property string value: myDB.getIncome() } } }
原因分析
核心问题在于ListElement是静态声明的元素:
- QML在解析
ListElement的时候,会把它当作静态常量来处理,只能接受字符串、数字这类编译时就能确定的字面量,无法执行运行时的函数调用(比如你调用的myDB.getIncome())。 - 而
Text组件的property是在组件实例化后,运行时阶段赋值的,这时候QML已经完成初始化,可以正常调用暴露的Python函数。
解决方案
这里提供两种简单可行的解决方法:
方法1:在QML中动态添加ListModel元素
利用Component.onCompleted信号,在组件加载完成后,通过mainModel.append()动态添加元素,此时就能正常调用Python函数:
import QtQuick 2.0 Rectangle { id: root width: 250; height: 450 color: "white" ListModel { id: mainModel } Component.onCompleted: { mainModel.append({ value: myDB.getIncome() }) } }
方法2:从Python端直接向ListModel写入数据
在Python代码中获取QML里的ListModel对象,然后直接添加数据,这种方式更适合数据来源本身就在Python端的场景:
修改main.py的主函数部分:
if __name__ == '__main__': myApp = QApplication(sys.argv) appLabel = QQuickView() mydb = MyDB() appLabel.rootContext().setContextProperty("myDB", mydb) appLabel.setSource(QUrl('main.qml')) # 获取QML中的ListModel对象 main_model = appLabel.rootObject().findChild(QObject, "mainModel") # 向模型添加数据 main_model.append({"value": mydb.getIncome()}) appLabel.show() myApp.exec_() sys.exit()
对应的QML只需要声明空的ListModel即可:
import QtQuick 2.0 Rectangle { id: root width: 250; height: 450 color: "white" ListModel { id: mainModel objectName: "mainModel" // 需要设置objectName才能在Python中找到 } }
内容的提问来源于stack exchange,提问作者user1179317
相关产品推荐
相关产品推荐

