QT Quick-信号与槽

QML 信号与槽

方式1

对于 QML 中的属性如果其值发生改变, QML 自动会发生相关信号

on<Property>Changed 这种格式

举例:

1
2
3
MouseArea {
onPressedChanged: console.log("value:" , pressed)
}

方式2

比较适合在同一个 QML 文件内

1
2
3
signal <name> (type parameter, type parameter)

on<Name>

例如:

1
2
3
4
signal testSignal(real x, real b)
testSignal(x, b) //执行 也就是 发送信号 类似 quick 中的 emit signal()

onTestSignal: console.log("xxx")// 槽 用于接收信号

举例:

1
2
3
4
5
6
7
8
9
10
11
Item {
signal clickTest();

MouseArea {
onPressed: {
clickTest()
}
}

onClickTest: consloe.log("received")
}

方式3

适合一对多或者跨 QML
断开就使用 disconnect 就好
1 : 跟信号在同一个范围,可这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
signal sendSignal();
MouseArea {
sendSignal()
}

Component.onCompleted: {
sendSignal.connect(send21)
sendSignal.connect(send22)
sendSignal.connect(send23)
}

function send21() {
console.log("1: received signal");
}

function send22() {
console.log("2: received signal");
}

function send23() {
console.log("3: received signal");
}

2:如果与信号不在同一范围

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
27
MyTest {
signal testT()
id : mytest
MouseArea {
onPressed: {
mytest.testT()
}
}
}

Component.onCompleted: {
mytest.testT.connect(send21) // mytest.testT.disconnect(send21)
mytest.testT.connect(send22)
mytest.testT.connect(send23)
}

function send21() {
console.log("1: received signal");
}

function send22() {
console.log("2: received signal");
}

function send23() {
console.log("3: received signal");
}

3:Connections 最主要的优势可以连接到没有定义在 QML 的东西
格式:

1
2
3
4
Connections {
target: 信号的来源
on<Signal>:
}

示例

1
2
3
4
5
6
Connections {
target: mytest
onTestT: {
send21();
}
}

QML中调用Python的函数

main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

Window {
width: 600; height: 400
visible: true
title: "主页面"

Button {
text: "打印"
onClicked: {
pageData.mlog("你好")
}
}
}

main.py

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
27
28
29
30
31
32
33
34
35
36
import os
from pathlib import Path
import sys

from PySide2.QtCore import *
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QApplication


# 1) 必须继承 QObject.
class MainWin(QObject):

# 2) 这里 Pycharm 会标记黄色警示, 忽略即可.
# 3) 第一个参数 self 不要丢了.
# noinspection PyCallingNonCallable
@Slot(str)
def mlog(self, s):
print(s)


if __name__ == '__main__':
app = QApplication()
engine = QQmlApplicationEngine()

# 4) 经测试, 必须先实例化 MainWin 赋给一个变量, 然后把变量传
pd = MainWin()

# 5) 如果我们没有赋给变量传进去, 而是直接实例化给第二个参数:
# engine.rootContext().setContextProperty('speaker', Speaker())
# 在 QML 中就会报错. 确实让人无法理解.
engine.rootContext().setContextProperty('pageData', pd)

# 6) 当把 Speaker 传入上下文后, 我们才可以 load 布局文件.
engine.load(QUrl.fromLocalFile('./main.qml'))
sys.exit(app.exec_())

Python 连接 QML 信号

(QML 发信号, Python 为槽)

main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

Window {
visible: true
width: 600; height: 400

signal mlog(string s)

Button {
text: "hello"
onClicked: mlog(text)
}
}

main.py

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 sys

from PySide2.QtCore import *
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QApplication


def log(s):
print(s)


if __name__ == '__main__':
app = QApplication()
engine = QQmlApplicationEngine()
engine.load(QUrl.fromLocalFile('./main.qml'))

# 获取 root 对象.
root = engine.rootObjects()[0] # type: QObject
# 找到目标对象. 由于我们的目标对象是 Window, 也就是 root 对象. 所以直接用.
target_view = root
# 绑定信号.
target_view.mlog.connect(log) # 前一个 mlog 是 qml 的信号, 后一个log是 Python 的

sys.exit(app.exec_())

Python获取控件

1
2
3
4
5
6
7
Text {
id: mytext
objectName: "mytext"
text: "Click Me"
font.pixelSize: 20
anchors.centerIn: parent
}

获取控件

1
txt_obj = engine.rootObjects()[0].findChild(QObject, "mytext")

获取控件属性的值:

1
txt_value = txt_obj.property("text")

设置控件属性的值:

1
txt_obj.setProperty("text", "Clicked!")