QML与Python通信

2015/07/05 08:29
阅读数 5.6K

对于Python3和QML通信,实际上就是 PyQt5+QML+Python3混合编程,这是必须的,因为QML做图形界面比较容易,但是做功能实现就用Python比较好,虽然QML也能嵌入 JavaScript代码进行实现,但是这样话还不如用Python来实现,代码简洁、易懂。

    对于以下的例子,参考了如下的连接:

Connecting QML signals in PySide:

http://qt-project.org/wiki/Connecting_QML_Signals_in_PySide 

PyQt 5.1.1 Reference Guide -> Support for Signals and Slots:

http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html?highlight=pyqtslot#PyQt5.QtCore.pyqtSlot

(1)QML显式的调用Python函数

定义一个类,并继承QtCore.QObject对象,并使用@修饰符修饰pyqtSlot

1
2
3
4
5
6
7
8
9
class MyClass(QObject):
    @pyqtSlot(str)    # 传递参数类型字符串
    def outputString(self, string):
        """
        功能: 创建一个槽
        参数: 输出的数据string
        返回值: 无
        """
        print(string)

创建rootContext对象,并使用setContextProperty(string, object)注册对象,这样在QML中就可以调用这个函数了。

1
2
context = view.rootContext()
context.setContextProperty("con", con)

如下是一个完整的例子:

这个例子运行后,如果点击鼠标的话,会在控制台打印字符串。

Python3代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: GBK -*-
from PyQt5.QtCore import QUrl, QObject, pyqtSlot
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
 
class MyClass(QObject):
    @pyqtSlot(str)    # 输入参数为str类型
    def outputString(self, string):
        """
        功能: 创建一个槽
        参数: 输出的数据string
        返回值: 无
        """
        print(string)
         
if __name__ == '__main__':
    path = 'test.qml'   # 加载的QML文件
    app = QGuiApplication([])
    view = QQuickView()
    con = MyClass()
    context = view.rootContext()
    context.setContextProperty("con", con)
    view.engine().quit.connect(app.quit)
    view.setSource(QUrl(path))
    view.show()
    app.exec_()

QML代码(文件名保存为test.qml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import QtQuick 2.0
Rectangle {
    width: 320; height: 240
    color: "lightgray"
    Text {
        id: txt
        text: "Clicked me"
        font.pixelSize: 20
        anchors.centerIn: parent
    }
    MouseArea {
        id: mouse_area
        anchors.fill: parent  // 有效区域
        onClicked: {
           con.outputString("Hello, Python3")
        }
    }
}

运行结果如下:

(2)QML调用Python函数,并返回

这个例子跟上一个相类似,只是这次调用Python的函数具有返回值功能。

以下是一个完整的例子:

运行程序后,点击鼠标,左上角会显示数字30。

Python3代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding: GBK -*-
from PyQt5.QtCore import QUrl, QObject, pyqtSlot
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
class MyClass(QObject):
    @pyqtSlot(int, result=str)    # 声明为槽,输入参数为int类型,返回值为str类型
    def returnValue(self, value):
        """
        功能: 创建一个槽
        参数: 整数value
        返回值: 字符串
        """
        return str(value+10)
if __name__ == '__main__':
    path = 'test.qml'   # 加载的QML文件
    app = QGuiApplication([])
    view = QQuickView()
    con = MyClass()
    context = view.rootContext()
    context.setContextProperty("con", con)
    view.engine().quit.connect(app.quit)
    view.setSource(QUrl(path))
    view.show()
    app.exec_()

QML代码(文件名保存为test.qml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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  // 有效区域
        onClicked: {
            console.log("test...")  // 控制台打印信息
            txt1.text = con.returnValue(20)
        }
    }
}

运行效果如下:

未点击鼠标时:                                                              点击鼠标之后:


(3)QML连接信号到Python

当QML触发事件的时候,发射一个信号给Python,此时Python调用一个函数。

先在QML中定义一个信号,

1
signal sendClicked(string str) // 定义信号

然后在捕获事件的时候,发射信号,

1
2
3
4
5
6
7
 MouseArea {
        id: mouse_area
        anchors.fill: parent  // 有效区域
        onClicked: {
            root.sendClicked("Hello, Python3")    # 发射信号到Python
        }
    }

最后Python中创建一个rootObject对象,然后连接这个对象,

1
2
3
4
5
6
7
def outputString(string):
    """
    功能: 输出字符串
    参数: 输出的数据string
    返回值: 无
    """
    print(string)
1
2
context = view.rootObject()
context.sendClicked.connect(outputString)   # 连接QML信号sendCLicked

以下是一个完整的例子:

这个例子中,当点击鼠标的时候,控制台会打印信息。

Python3代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# -*- coding: GBK -*-
 
from PyQt5.QtCore import QUrl, pyqtSlot
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
 
def outputString(string):
    """
    功能: 输出字符串
    参数: 输出的数据string
    返回值: 无
    """
    print(string)
 
if __name__ == '__main__':
    path = 'test.qml'   # 加载的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_()

QML代码(文件名保存为test.qml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
        }
    }
}

运行结果如下:


(4)Python调用QML函数

QML中创建一个函数,

1
2
3
function updateRotater() {
    rotater.angle += 45
}

Python中创建一个rootObject对象,并连接这个函数,

1
2
root = view.rootObject()
timer.timeout.connect(root.updateRotater)

以下是一个完整的例子:

例子中,每隔1s,指针会旋转45°。

Python3代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- coding: GBK -*-
 
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)
 
    app.exec_()

QML代码(文件名保存为test.qml): 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import QtQuick 2.0
 
Rectangle {
    id: page
    width: 500; height: 200
    color: "lightgray"
 
    function updateRotater() {
        rotater.angle += 45
    }
 
    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
        }
    }
}

运行结果如下: 


本人水平有限,如果有疏漏之处,欢迎指点。


展开阅读全文
打赏
0
13 收藏
分享
加载中
本文的(3)QML连接信号到Python,我遇到了问题啊。
Traceback (most recent call last):
File "F:/a代码/ate/adding/ate_get/qml_pyqt_python/QML连接信号到Python/main_llq.py", line 26, in <module>
context.sendClicked.connect(outputString) # 连接QML信号sendCLicked
AttributeError: 'NoneType' object has no attribute 'sendClicked'


context = view.rootObject() 打印出来的context 是None,你们是这样的吗
03/23 11:13
回复
举报
参考https://my.oschina.net/u/1275030/blog/184899已解决,因为view下没object
03/23 11:24
回复
举报
openthings博主
👍
03/23 14:46
回复
举报
慢慢的发现用这个做一般的工业产品快速开发太方便了
2015/11/22 11:05
回复
举报
明天来实验室看看此文,先马克一下
2015/10/24 23:36
回复
举报
更多评论
打赏
5 评论
13 收藏
0
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部