关于qt:PyQt5 QML信号到Python插槽?

PyQt5 QML Signal to Python Slot?

python方法/插槽如何连接到QML信号? 看起来QtObject.connect()曾经在PyQt4中工作,但在PyQt5中不再可用。

1
2
3
4
5
6
7
8
9
10
11
12
#Sample QML File (stack.qml)

import QtQuick 2.0

Rectangle {
    MouseArea {
        anchors.fill: parent
        onClicked: {
           // relay this to python
        }
    }
}

-

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
#Sample Python File
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView

if __name__ == '__main__':
    import os
    import sys

    app = QGuiApplication(sys.argv)

    view = QQuickView()
    view.setWidth(500)
    view.setHeight(500)
    view.setTitle('Hello PyQt')
    view.setResizeMode(QQuickView.SizeRootObjectToView)
    view.setSource(QUrl.fromLocalFile(os.path.join(os.path.dirname(__file__),'stack.qml')))

    def on_qml_mouse_clicked(mouse_event):
        print 'mouse clicked'

    view.show()
    qml_rectangle = view.rootObject()

    # this technique doesn't work #############################
    qml_rectangle.mousePressEvent.connect(on_qml_mouse_clicked)

    sys.exit(app.exec_())

一些PyQT示例通过" setContextProperty"将对象传递到QML上下文中,然后将QML事件中继到该对象上的插槽,但是这种方法似乎是round回的。 有没有更好的办法?


qml_rectangle.mousePressEvent不是信号,它是在鼠标事件上调用的事件处理程序,因此您无法连接到它。您可以将其替换为处理程序函数(qml_rectangle.mousePressEvent = on_qml_mouse_clicked),但这不是使用Qt的一种非常干净的方法。

更好的方法是在qml文件中定义一个信号,并从矩形的onClicked处理程序中发出该信号:

1
2
3
4
5
6
7
8
9
10
11
import QtQuick 2.0

Rectangle {
    signal clicked()
    MouseArea {
        anchors.fill: parent
        onClicked: {
           parent.clicked()  // emit the parent's signal
        }
    }
}

然后,您可以从python代码连接到它:

1
2
3
4
5
6
...
def on_qml_mouse_clicked():
    print('mouse clicked')

qml_rectangle.clicked.connect(on_qml_mouse_clicked)
...

我建议子类化QQuickView并在其根上下文中设置属性,例如MainWindow。现在,您需要做的就是在类中添加带有@pyqtSlot('QString')之类装饰的函数,然后可以使用onClicked设置事件处理程序:MainWindow.FunctionName(Arguments_According_To_Decoration)

然后您的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
#!/bin/env python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore    import pyqtSlot
from PyQt5.QtCore    import QUrl
from PyQt5.QtQuick   import QQuickView
from PyQt5.QtWidgets import QApplication
import sys

class MainWindow(QQuickView):
    def __init__(self):
        super().__init__()
        self.setSource(QUrl('sample.qml'))
        self.rootContext().setContextProperty("MainWindow", self)
        self.show()

    @pyqtSlot('QString')
    def Print(self, value):
        print(value)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

和sample.qml一样

1
2
3
4
5
6
7
8
9
10
11
import QtQuick          2.0
import QtQuick.Controls 2.2

Rectangle {
    width: 200; height: 200

    Button {
      text:"print Hello World"
      onClicked: MainWindow.Print('hello world')
    }
}

您可以在文档中找到更多信息

http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html