python和qml混合开发,一般都是python做逻辑,qml做界面,所以大部分都是qml调用python中的逻辑,所以先说最常用的和使用范围最广的。
第一,qml调用python函数
python中的main.py
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import qmlRegisterType, QQmlApplicationEngine
from PySide2.QtCore import Slot, QObject, QUrl
class MyClass(QObject):
@Slot(int, result=str) #声明为槽,输入参数为int类型,返回值为str类型
def returnValue(self, value):
return str(value+10)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
con = MyClass()
engine.rootContext().setContextProperty("con",con)
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
main.qml
import QtQuick 2.0
Window{
id: root
width: 320; height: 240
color: "lightgray"
Text {
id: txt
text: "Clicked me"
font.pixelSize: 20
anchors.centerIn: parent
}
Text {
id: txt1
text: "..."
font.pixelSize: 20
}
MouseArea {
id: mouse_area
anchors.fill: parent
onClicked: {
console.log("test...")
txt1.text = con.returnValue(20)
}
}
}
第二,QML连接信号到Python
当QML触发事件的时候,发射一个信号给Python,此时Python调用一个函数
先在QML中定义一个信号,然后在捕获事件的时候,发射信号。最后Python中创建一个rootObject对象,然后连接这个对象
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
def outputString(string):
print(string)
if __name__ == '__main__':
path = 'test.qml'
app = QGuiApplication([])
view = QQuickView()
view.engine().quit.connect(app.quit)
view.setSource(QUrl(path))
view.show()
context = view.rootObject()
context.sendClicked.connect(outputString) #连接QML信号sendClicked
app.exec_()
import QtQuick 2.0
Rectangle {
id: root
width: 320; height: 240
color: "lightgray"
signal sendClicked(string str) //定义信号
Text {
id: txt
text: "Clicked me"
font.pixelSize: 20
anchors.centerIn: parent
}
MouseArea {
id: mouse_area
anchors.fill: parent //有效区域
onClicked: {
root.sendClicked("Hello, Python3") //发射信号到Python
}
}
}
第三,Python调用QML函数
QML中创建一个函数,Python中创建一个rootObject对象,并连接这个函数
from PyQt5.QtCore import QUrl, QTimer
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
if __name__ == '__main__':
path = 'test.qml' #加载的QML文件
app = QGuiApplication([])
view = QQuickView()
view.engine().quit.connect(app.quit)
view.setSource(QUrl(path))
view.show()
timer = QTimer()
timer.start(2000)
root = view.rootObject()
timer.timeout.connect(root.updateRotater) #调用QML函数
app.exec_()
import QtQuick 2.0
Rectangle {
id: page
width: 500; height: 200
color: "lightgray"
function updateRotater() {// 定义函数
rotater.angle += 5
}
Rectangle {
id: rotater
property real angle: 0
x: 240; y: 95
width: 100; height: 5
color: "black"
transform: Rotation {
origin.x: 10; origin.y: 5
angle: rotater.angle
}
}
}
第四,python操作qml对象
如何在python里获得qml里的对象?
4.1 获取根对象
使用QQmlApplicationEngine类的rootObjects方法,返回的是一个列表,取索引0即是根对象。
engine = QQmlApplicationEngine()
engine.load('qml-test.qml')
root_obj = engine.rootObjects()[0]
这样就会获得id为window的ApplicationWindow对象。
4.2 如何获取任意对象
需要在qml文件中加入objecName属性!暂时还不知道如何获取不是ApplicationWindow下的对象,知道的可以麻烦告知下
QML:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
width: 250
height: 500
visible: true
Text {
id: txt
objectName: "txt"
text: "Click Me"
font.pixelSize: 20
anchors.centerIn: parent
}
}
Python:
engine = QQmlApplicationEngine()
engine.load('qml-test.qml')
txt_obj = engine.rootObjects()[0].findChild(QObject, "txt")
4.3. 如何在python里读取和设置qml对象的属性和值?
4.3.1 读取对象的属性(如Text对象)
首先通过 findChild 获取Text对象(注意 txt 是qml文件里的 objectName):
txt_obj = engine.rootObjects()[0].findChild(QObject, "txt")
txt_value = txt_obj.property("text")
4.3.2 设置对象的属性
使用setProperty方法可以更改对象的属性值。
txt_obj.setProperty("text", "Clicked!")
完整代码:
import sys
from PyQt5.QtCore import QObject
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load('qml-test.qml')
# 根对象
root_obj = engine.rootObjects()[0]
# Text对象
txt_obj = engine.rootObjects()[0].findChild(QObject, "txt")
# 读取属性值
txt_value = txt_obj.property("text")
# 设置属性值
txt_obj.setProperty("text", "Clicked!")
sys.exit(app.exec())
第五,信号/槽机制
把python类注册成qml类,可以直接在qml中使用
qmlRegisterType(CameraOpencv,'MyCamera',1,0,'MyCustomOpenCVItem')
class CameraOpencv(QQuickPaintedItem):
activateVideoChanged = Signal() #是否开启视频流
def getVideoState(self):
return self.activateVideoStream
def setVideoState(self, state):
if self.activateVideoStream != state:
if state == False:
self._timer1.stop()
else:
self._timer1.start(16)
self.activateVideoStream = state
activateVideo = Property(bool, fget=getVideoState, fset=setVideoState, notify=activateVideoChanged)
直接在QML中使用
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import MyCamera 1.0
Item{
id:root
property alias myCustomOpenCVItem: myCustomOpenCVItem
Rectangle{
color:"black"
anchors.fill: parent
MyCustomOpenCVItem{
id:myCustomOpenCVItem
objectName:"camera_win"
anchors.fill:parent
}
MouseArea{
anchors.fill: parent
onClicked: {
content.contentMiddle.myCustomOpenCVItem.save()
}
}
}
}