Python中PyQt5与QML交互感觉比较繁琐,如何优化?

繁琐主要体现在:

1、Python 中不能使用 QML 中的 id 查找控件,需要用 objectName,,一般这两者值是完全一样的,重复劳动

ComboBox {
	id: cmbPort
	objectName: "cmbPort"
	Layout.minimumWidth: 100 * 2 + 10 * 2 + lblSer.width
	model: ports
}

2、pyqtProperty 不太好用,,搞了好久没用起来,放弃了

3、Python 中无法直接使用 QML 中的控件,必须用 findObject 在 Python 中再定义一遍

self.cmbPort = self.win.findChild(QObject, 'cmbPort')
self.cmbBaud = self.win.findChild(QObject, 'cmbBaud')
self.cmbData = self.win.findChild(QObject, 'cmbData')
self.cmbParity = self.win.findChild(QObject, 'cmbParity')
self.cmbStop = self.win.findChild(QObject, 'cmbStop')

self.txtMain = self.win.findChild(QObject, ‘txtMain’) self.txtSend = self.win.findChild(QObject, ‘txtSend’)

self.chkRHex = self.win.findChild(QObject, ‘chkRHex’) self.chkWave = self.win.findChild(QObject, ‘chkWave’) self.chkTHex = self.win.findChild(QObject, ‘chkTHex’) self.chkLine = self.win.findChild(QObject, ‘chkLine’) self.chkTime = self.win.findChild(QObject, ‘chkTime’)

self.btnOpen = self.win.findChild(QObject, ‘btnOpen’)

4、Python 中不能直接访问 QML 控件的属性,而需要用 property、setProperty 间接访问

比如 CombBox 控件有 currentText 属性,不能用 self.cmbPort.currentText 访问,而必须用 self.cmbPort.property('currentText')访问

5、文档资料很少,,没有应用示例

代码在此:https://github.com/XIVN1987/QmlSer

运行效果:

QmlSer


Python中PyQt5与QML交互感觉比较繁琐,如何优化?

11 回复

好几次想试试 QML,但还是觉得费劲,干脆就还是 designer 直接排了,省事还可视化


PyQt5里用QML确实容易搞出一堆信号槽的绑定代码,看着就头大。其实可以换个思路,用QQmlProperty或者直接暴露Python对象给QML来简化。

比如把Python对象注册成QML上下文属性,这样在QML里就能直接调它的方法和属性。下面是个完整例子:

import sys
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine

class Backend(QObject):
    def __init__(self):
        super().__init__()
        self._message = "Hello from Python"
    
    @pyqtProperty(str)
    def message(self):
        return self._message
    
    @pyqtSlot(str)
    def update_message(self, text):
        self._message = text
        print(f"Message updated: {text}")

app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()

backend = Backend()
engine.rootContext().setContextProperty("backend", backend)

engine.load('main.qml')  # QML文件里可以直接用backend对象

if not engine.rootObjects():
    sys.exit(-1)

sys.exit(app.exec_())

对应的QML文件(main.qml):

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    
    Text {
        text: backend.message  // 直接访问Python属性
        anchors.centerIn: parent
    }
    
    Button {
        text: "Click me"
        onClicked: backend.update_message("New message from QML")  // 直接调用Python方法
        anchors.bottom: parent.bottom
    }
}

这样就不用到处定义信号槽了,QML里直接操作Python对象,代码清爽很多。建议用上下文属性暴露核心对象。


是的,现在看来 Qt Widget 还是要比 Qt Quick 用起来更简单、快捷,,希望 Qt 官方的 Python 绑定能简化 Python 和 QML 的交互

不过 Widget 是给电脑桌面 GUI 设计的,没有考虑手机、平板等设备,,如果想开发手机应用的话可能还是得上 Qt Quick

PyQt 打包方便吗


挺简单,,“ pyinstaller -F xxx.py ”一条命令即可,,打包后最小 15M,也还能接受

lz 大佬,请教一下,我用 pyinstaller 打包后的 pyqt 应用在 win 下启动十分缓慢,要 40s 左右,运行倒挺流畅的。是什么参数配置不对吗?


打包速度很快,不到一分钟(我做的程序都比较小)


确实比直接运行.py 慢,,我自己用都是.py ,,只有给别人用的时候才打包
不过好像也没这么慢吧,,可能你的程序功能比较复杂吧,,

为什么要这么专业呢?随便写个 UI 就好了。。

感觉最大的硬伤是 QML 没有文档。

楼主你 github 这个 qml 我 qml.rootContext().setContextProperty(‘Ser’, QmlSer(qml.rootContext(), qml.rootObjects()[0])), 读取不到 rootObjects 啊

回到顶部