PyQt和QML:如何在一个插槽或函数中处理多个信号

时间:2017-01-07 22:08:38

标签: python qml pyqt5

我现在花了很长时间才弄清楚如何将QML信号连接到python中的插槽,以及如何再次与QML GUI进行通信。但我无法弄清楚如何在python中向同一个插槽/函数发送多个GUI输入。

以下是应该发生的事情的基本示例: 用户操纵GUI中的SpinBox,它们的总和再次显示在GUI中。 我假设这是通过将几个信号路由到一个插槽或通过将每个信号路由到单个插槽并让python以某种方式进行组合来完成的。但显然pyqt插槽也不允许“返回”。

非常感谢帮助!

QML: (评论的行是我认为可行的,但它没有。当没有注释信号行时,它会产生“预期的令牌'标识符'。”

import QtQuick 2.6
import QtQuick.Controls 2.0

ApplicationWindow{
    visible:true
    width:200
    height:300
    id:window
    title: "Signal/Slot Test"

    Rectangle{

        //signal somethingChanged(int, int)

        //function exportSignals() {
        //    somethingChanged(spin1.value, spin2.value)
        //}

        Column {
            spacing: 20
            width: parent.width


            SpinBox {
                id: spin1
                signal sig_spin1(int spin1_int)
                objectName: "spin1"
                value: 50
                width: 120
                editable: true
                Component.onCompleted: {
                    console.log("Spin1: " + spin1.value)
                    sig_spin1(spin1.value)
                    //exportSignals()
                }
                onValueChanged: {
                    console.log("Spin1: " + spin1.value)
                    sig_spin1(spin1.value)
                    //exportSignals()
                }
            }

            SpinBox {
                id: spin2
                signal sig_spin2(int spin2_int)
                objectName: "spin2"
                value: 50
                width: 120
                editable: true
                Component.onCompleted: {
                    console.log("Spin2: " + spin2.value)
                    sig_spin2(spin2.value)
                    //exportSignals()
                }
                onValueChanged: {
                    console.log("Spin2: " + spin2.value)
                    sig_spin2(spin2.value)
                    //exportSignals()
                }
            }

            Label {
                id: label_spin1
                objectName: "label_spin1"
                text: "Start Value"
            }

            Label {
                id: label_spin2
                objectName: "label_spin2"
                text: "Start Value"
            }

            Label {
                id: label_result
                objectName: "label_result"
                text: "Sum"
            }

        }
    }
}

和python代码:

import sys
from PyQt5.QtCore import QObject, QUrl, Qt, pyqtSlot
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine


def spin1_update(spin1_int):
    print("Spin 1 updated")
    label_spin1 = win.findChild(QObject, "label_spin1")
    label_spin1.setProperty("text", spin1_int)

def spin2_update(spin2_int):
    print("Spin 2 updated")
    label_spin2 = win.findChild(QObject, "label_spin2")
    label_spin2.setProperty("text", spin2_int)


def spin_sum(spin1_int, spin2_int):
    my_sum = spin1_int + spin2_int
    label_result = win.findChild(QObject, "label_result")
    label_result.setProperty("text", my_sum)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    engine = QQmlApplicationEngine()
    engine.load('main.qml')
    win = engine.rootObjects()[0]

    spin1 = win.findChild(QObject, "spin1")
    spin1.sig_spin1.connect(spin1_update)

    spin2 = win.findChild(QObject, "spin2")
    spin2.sig_spin2.connect(spin2_update)

    #win.exportSignals.connect()


    win.show()
    sys.exit(app.exec_())

更新。为了完整性,一个工作示例: main.py:

import sys

from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty,     QCoreApplication, QObject, QUrl
from PyQt5.QtQml import QQmlEngine, QQmlApplicationEngine
from PyQt5.QtWidgets import QApplication



class GuiInteraction(QObject):


    def __init__(self, parent=None):
        super().__init__(parent)


    @pyqtSlot(int, int, result=int)
    def get_sum(self, spin1, spin2):
        print("Spin1 from python: ", spin1)
        print("Spin2 from the same python slot: ", spin2)
        my_sum = spin1 + spin2
        print(my_sum)
        print()
        return my_sum




if __name__ == "__main__":
    app = QApplication(sys.argv)
    guiInteraction = GuiInteraction()

    engine = QQmlApplicationEngine()
    ctx = engine.rootContext()
    ctx.setContextProperty("guiInteraction", guiInteraction)
    engine.load('main.qml')
    win = engine.rootObjects()[0]


    win.show()
    sys.exit(app.exec_())

和main.qml:

import QtQuick 2.6
import QtQuick.Controls 2.0

ApplicationWindow{
    visible:true
    width:200
    height:300
    id:window
    title: "Signal/Slot Test"



    Rectangle{

        Column {
            spacing: 20
            width: parent.width


            SpinBox {
                id: spin1
                value: 50
                width: 120
                editable: true
                Component.onCompleted: {
                    console.log("Spin1: " + spin1.value)

                }
                onValueChanged: {
                    console.log("Spin1: " + spin1.value)

                    label_result.text = guiInteraction.get_sum(spin1.value, spin2.value)
                }
            }

            SpinBox {
                id: spin2
                value: 50
                width: 120
                editable: true
                Component.onCompleted: {
                    console.log("Spin2: " + spin2.value)

                }
                onValueChanged: {
                    console.log("Spin2: " + spin2.value)
                    label_result.text = guiInteraction.get_sum(spin1.value, spin2.value)
                }
            }


            Label {
                id: label_result
                objectName: "label_result"
                text: "Nothing yet."
            }

        }
    }
}

2 个答案:

答案 0 :(得分:3)

首先,你不会在Python或C ++方面做任何事情,特别是不更新价值标签。

对于值标签,您只需使用属性绑定,例如:

Label {
    text: "Start value: " + spin1.value
}

对于像总和一样的微不足道的计算,你也会这样做。

现在,假设计算更复杂并且您希望在Python端执行此操作,那么您将不需要QML端的任何信号。

相反,一个选项是在Python中有一个QObject派生类,它提供一个带有两个参数的插槽。

该对象的实例将通过QML引擎setContextProperty()的{​​{1}}机制向QML公开。 每个旋转盒'然后,rootContext()处理程序可以使用这两个值调用此插槽。

对于结果,slot可以返回值,或者对象可以提供由槽更新的结果属性,并在QML中用作结果标签上的绑定。

答案 1 :(得分:0)

您无法按照建议的方式将两个信号连接到同一个插槽。所有信号都会触发插槽中的代码运行一次;它并不像电子产品中的物理线那样真正的连续连接(这是我想象你可能想象的)。

当一个旋转框值发生变化时,您需要检索另一个旋转框值(来自旋转框本身,来自标签,或来自您已存储它的另一个变量)以进行添加。例如:

def spin1_update(spin1_int):
    print("Spin 1 updated")
    label_spin1 = win.findChild(QObject, "label_spin1")
    label_spin1.setProperty("text", spin1_int)
    spin_sum()

def spin2_update(spin2_int):
    print("Spin 2 updated")
    label_spin2 = win.findChild(QObject, "label_spin2")
    label_spin2.setProperty("text", spin2_int)
    spin_sum()

def spin_sum():
    spin1 = win.findChild(QObject, "spin1")
    spin2 = win.findChild(QObject, "spin2")
    my_sum = spin1.value() + spin2.value()

    label_result = win.findChild(QObject, "label_result")
    label_result.setProperty("text", my_sum)

在这种情况下,不需要将spin_sum()连接到任何东西。它已经由前两个插槽函数直接调用。