python和qml混合編程,過程中免不了有很多需要交互數(shù)據(jù)和參數(shù)的情況,雖然現(xiàn)在項目基本完成,回過頭來總結(jié)下參數(shù)傳遞,以防后期查閱,其中有不少借鑒的地方。主要還是以備后期查看。
一、QML顯式的調(diào)用Python函數(shù)(無返回)
#!/usr/bin/env python
# qml-test1.py
'''
定義一個類,并繼承QtCore.QObject對象,并使用@修飾符修飾pyqtSlot
創(chuàng)建rootContext對象,并使用setContextProperty(string, object)注冊對象,
這樣在QML中就可以調(diào)用這個函數(shù)了。
這個例子運行后,如果點擊鼠標的話,會在控制臺打印字符串。
'''
from PyQt5.QtQuick import QQuickView
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MyClass(QObject):
@pyqtSlot(str) # 輸入?yún)?shù)為str類型
def outputString(self, string):
print(string)
@pyqtSlot(list) # list可以被識別
def outputlist(self,qmllist):
print(qmllist)
@pyqtSlot(QVariant) # dict不能
def outputdict(self,qmldict):
print(qmldict.toVariant(),type(qmldict.toVariant()))
if __name__ == '__main__':
app = QGuiApplication([])
path = 'test.qml' # 加載的QML文件
con = MyClass()
view = QQuickView()
view.engine().quit.connect(app.quit)
view.setSource(QUrl(path))
context = view.rootContext()
context.setContextProperty("con", con)
view.setFramePosition(QPoint(100,100))
view.show()
app.exec_()
//test.qml
import QtQuick 2.0
Rectangle {
width: 320; height: 240
color: "red"
Text {
id: txt
text: "Clicked btn"
font.pixelSize: 20
anchors.centerIn: parent
}
MouseArea {
id: mouse_area
anchors.fill: parent // 有效區(qū)域
onClicked: {
con.outputString("Hello, Python3") //QML顯式的調(diào)用Python函數(shù)
con.outputlist(["Hello, Python3"]) //QML顯式的調(diào)用Python函數(shù)
con.outputdict({"Hello": "Python3"}) //QML顯式的調(diào)用Python函數(shù)
}
}
}
二、QML顯式的調(diào)用Python函數(shù)(有返回)
#!/usr/bin/env python
# qml-test2.py
'''
這個例子跟上一個相類似,只是這次調(diào)用Python的函數(shù)具有返回值功能。
運行程序后,點擊鼠標,左上角會顯示數(shù)字30。
'''
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtQuick import *
from PyQt5.QtQml import *
class MyClass(QObject):
@pyqtSlot(int, result=str)
def returnValue(self, value):
return str(value + 10)
@pyqtSlot(int, result=list)
def returnList(self, value):
return [1, 2, 3]
# @pyqtSlot(int,result=QVariant)
# def returnDict(self, value):
# return QJsonDocument.fromJson(b'{"test": null}')
@pyqtSlot(result=QVariant)
def returnDict(self, ):
return {"a": 1, "b": 2} # 鍵必須是字符串
# @pyqtSlot(int,result=QVariant)
# def returnDict(self, value):
# return QJsonDocument.fromJson(b'{"test": null}')
# # return QVariant()
# # return QJsonValue()
if __name__ == '__main__':
app = QGuiApplication([])
path = 'test2.qml' # 加載的QML文件
con = MyClass()
view = QQuickView()
view.engine().quit.connect(app.quit)
view.setSource(QUrl(path))
context = view.rootContext()
context.setContextProperty("con", con)
view.show()
app.exec_()
// test2.qml
import QtQuick 2.0
Rectangle {
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 // 有效區(qū)域
onClicked: {
console.log("test...") // 控制臺打印信息
txt1.text = con.returnValue(20) //QML顯式的調(diào)用Python函數(shù)
console.log(con.returnList(20))
var data = con.returnDict(20)
for(var key in data){
var value = data[key]
console.log(key, ": ", value)
}
}
}
}
三、QML連接信號到Python
#!/usr/bin/env python
# qml-test3.py
'''
當(dāng)QML觸發(fā)事件的時候,發(fā)射一個信號給Python,此時Python調(diào)用一個函數(shù)。
先在QML中定義一個信號,
然后在捕獲事件的時候,發(fā)射信號,
最后Python中創(chuàng)建一個rootObject對象,然后連接這個對象,
這個例子中,當(dāng)點擊鼠標的時候,控制臺會打印信息。
'''
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def outputString(string):
print(string)
@pyqtSlot(list, result=list) # 并不會自動識別,還是需要toVariant()
def outputList(string):
print(string.toVariant())
def outputDict(string):
print(string.toVariant()) # 整數(shù)的鍵過來會自動變字符串
if __name__ == '__main__':
path = 'test3.qml' # 加載的QML文件
app = QGuiApplication([])
view = QQuickView()
view.engine().quit.connect(app.quit)
view.setSource(QUrl(path))
view.show()
# 需要信號連接
context = view.rootObject()
context.sendClicked1.connect(outputString) # 連接QML信號sendCLicked
context.sendClicked2.connect(outputList) # 連接QML信號sendCLicked
context.sendClicked3.connect(outputDict) # 連接QML信號sendCLicked
context.sendClicked31.connect(outputDict) # 連接QML信號sendCLicked
app.exec_()
// test3.qml
import QtQuick 2.0
Rectangle {
id: root
width: 320; height: 240
color: "lightgray"
signal sendClicked1(string str) // 定義信號
signal sendClicked2(var list) // 定義信號
signal sendClicked3(var dict) // 定義信號
signal sendClicked31(var dict) // 定義信號
Text {
id: txt
text: "Clicked me"
font.pixelSize: 20
anchors.centerIn: parent
}
MouseArea {
id: mouse_area
anchors.fill: parent //有效區(qū)域
onClicked: {
root.sendClicked1("Hello, Python3")//發(fā)射信號到Python
root.sendClicked2(["Hello, Python3"])//發(fā)射信號到Python
root.sendClicked3({"Hello":"Python3"})//發(fā)射信號到Python
root.sendClicked31({1:"Python3"})//發(fā)射信號到Python
}
}
}
四、把 python 類注冊成 qml 類
qmlRegisterType(CameraOpencv,'MyCamera',1,0,'MyCustomOpenCVItem')
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()
}
}
}
}
五、設(shè)置可在 qml 中用的屬性
方法一:
self._goodsName = '' #當(dāng)前商品名稱
goodsNameChanged = pyqtSignal(str)
@pyqtProperty(str,notify=goodsNameChanged)
def goodsName(self):
return self._goodsName
@goodsName.setter
def goodsName(self, value):
self._goodsName = value
self.goodsNameChanged.emit(value)
方法二:
projectName = pyqtProperty(str, fget=getProjectValue, fset= setProjectValue, notify=projectNameChanged)
.qml 動態(tài)設(shè)置 component
function getLoader (){
switch (uploadStatus)
{
case "imgUploadFail":
return uploadFail
case "imgUploadOK":
return uploadOK
case "imgUploading":
return uploading
case "imgUploadReady":
return null
default:
return null
}
}
Loader{
id:currLoad
anchors.fill:parent
sourceComponent:getLoader()
}