zoukankan      html  css  js  c++  java
  • 如何实现PyQt5与QML响应彼此发送的信号?

    对于PyQt5+QML+Python3混合编程,如何实现PyQt5与QML响应彼此发送的信号,这是一个棘手的问题。

    大抵有如下五种方式:

    要运行下面五个例子,千万不能在eric6中运行,会报错。错误信息是:qml-test.py文件的第一个字符是无效的标识符

    (1)QML显式的调用Python函数,无返回值

    #文件名:qml-test.py
    #文件名:test.qml
    #!/usr/bin/env python
    '''
    (1)QML显式的调用Python函数
    
    定义一个类,并继承QtCore.QObject对象,并使用@修饰符修饰pyqtSlot
    
    创建rootContext对象,并使用setContextProperty(string, object)注册对象,    
    这样在QML中就可以调用这个函数了。 这个例子运行后,如果点击鼠标的话,会在控制台打印字符串。
    ''' 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): 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_()
    import QtQuick 2.0
    
    Rectangle {
         320; height: 240
        color: "lightblue"
        Text {
            id: txt
            text: "Clicked me"
            font.pixelSize: 20
            anchors.centerIn: parent
        }
        MouseArea {
            id: mouse_area
            anchors.fill: parent  // 有效区域
            onClicked: {
               con.outputString("Hello, Python3") //QML显式的调用Python函数   
            }
        }
    }

    (2)QML显式的调用Python函数,有返回值

    #文件名:qml-test2.py
    #文件名:test2.qml
    #!/usr/bin/env python
    '''
    (2)QML显式的调用Python函数,并有返回
    
    这个例子跟上一个相类似,只是这次调用Python的函数具有返回值功能。
    
    运行程序后,点击鼠标,左上角会显示数字30。
    '''
    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):
            return str(value+10)
    
    if __name__ == '__main__':
        path = 'test2.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_()
    import QtQuick 2.0
    
    Rectangle {
        id: root
         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函数    
            }
        }
    }

    (3)QML连接信号到Python

    #文件名:qml-test3.py
    #文件名:test3.qml
    #!/usr/bin/env python
    '''
    (3)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 = 'test3.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_()
    import QtQuick 2.0
     
    Rectangle {
        id: root
         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-test4.py
    #文件名:test4.qml
    # -*- coding: utf-8 -*-
    '''
    (4)Python调用QML函数
    
    QML中创建一个函数,
    
    Python中创建一个rootObject对象,并连接这个函数,
    
    例子中,每隔1s,指针会旋转45 deg;。
    '''
    from PyQt5.QtCore import QUrl, QTimer
    from PyQt5.QtGui import QGuiApplication
    from PyQt5.QtQuick import QQuickView
     
    if __name__ == '__main__':
        path = 'test4.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
         500; height: 200
        color: "lightgray"
     
        function updateRotater() {// 定义函数                             
            rotater.angle += 5
        }
     
        Rectangle {
            id: rotater
            property real angle : 0
            x: 240; y: 95
             100; height: 5
            color: "black"
     
            transform: Rotation {
                origin.x: 10; origin.y: 5
                angle: rotater.angle
            }
        }
    }

     (5)信号/槽 机制

    #文件名:qml-test5.py
    #文件名:test5.qml
    from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QRectF, Qt, QUrl
    from PyQt5.QtGui import QColor, QGuiApplication, QPainter, QPen
    from PyQt5.QtQml import qmlRegisterType
    from PyQt5.QtQuick import QQuickPaintedItem, QQuickView
    
    
    class PieChart(QQuickPaintedItem):
    
        chartCleared = pyqtSignal() # 定义信号
    
        @pyqtProperty(str)
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name
    
        @pyqtProperty(QColor)
        def color(self):
            return self._color
    
        @color.setter
        def color(self, color):
            self._color = QColor(color)
    
        def __init__(self, parent=None):
            super(PieChart, self).__init__(parent)
    
            self._name = ''
            self._color = QColor()
    
        def paint(self, painter):
            painter.setPen(QPen(self._color, 2))
            painter.setRenderHints(QPainter.Antialiasing, True)
    
            rect = QRectF(0, 0, self.width(), self.height()).adjusted(1, 1, -1, -1)
            painter.drawPie(rect, 90 * 16, 290 * 16)
    
        @pyqtSlot()
        def clearChart(self):
            self.color = QColor(Qt.transparent)
            self.update()
    
            self.chartCleared.emit() # 发射信号
    
    
    if __name__ == '__main__':
        import os
        import sys
    
        app = QGuiApplication(sys.argv)
    
        qmlRegisterType(PieChart, "Charts", 1, 0, "PieChart")
    
        view = QQuickView()
        view.setResizeMode(QQuickView.SizeRootObjectToView)
        view.setSource(
                QUrl.fromLocalFile(
                        os.path.join(os.path.dirname(__file__),'tes5.qml')))
        view.show()
    
        sys.exit(app.exec_())
    import Charts 1.0
    import QtQuick 2.0
    
    Item {
         300; height: 200
    
        PieChart {
            id: aPieChart
            anchors.centerIn: parent
             100; height: 100
            color: "red"
    
            onChartCleared: console.log("The chart has been cleared") //
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: aPieChart.clearChart()
        }
    
        Text {
            anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
            text: "Click anywhere to clear the chart"
        }
    }

    参考:

    【QML与Python通信】

    http://my.oschina.net/u/1275030/blog/186341

    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

  • 相关阅读:
    [HEOI2013]Eden 的新背包问题
    [UOJ#77]A+B Problem
    [CodeForces]786B Legacy
    [LUOGU]P4098[HEOI2013]ALO
    [BZOJ3207]花神的嘲讽计划
    [LUOGU]P2633 Count on a tree
    【东莞市选2007】拦截导弹
    [JZOJ] 3462. 【NOIP2013模拟联考5】休息(rest)
    [BZOJ] 2705: [SDOI2012]Longge的问题
    [BZOJ] 1191: [HNOI2006]超级英雄Hero
  • 原文地址:https://www.cnblogs.com/hhh5460/p/4237863.html
Copyright © 2011-2022 走看看