2017-01-07 12 views
0

QML信号をPythonのスロットに接続する方法と、QML GUIとのやりとりの仕方を理解するのにかなり時間を費やしました。しかし、私はどのように複数のGUIの入力を同じスロット/関数にPythonで送るかを理解することはできません。PyQtとQML:1つのスロットまたは関数で複数の信号を処理する方法

ここには何が起きるべきかの基本的な例があります: ユーザーはGUIのスピンボックスを操作し、それらの合計が再びGUIに表示されます。 これは、いくつかのシグナルを1つのスロットにルーティングすることによって、または各シグナルを個々のスロットにルーティングして、何らかの形で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_()) 

UPDATE完全を期すため、作業例: 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." 
      } 

     } 
    } 
} 
+0

なぜPythonを使ってラベルの値を設定したいのですか? C++から値を設定できるC++と同じように、あなたはそうするように勧められませんが、PyQtでそれを行うのは良いスタイルだとは思っていません。 – derM

+0

これはどうやって動作するのか誤解するかもしれません。私はC++については分かりませんが、Pythonについて知っています。当然、私はPythonでqml guiに設定できる値からいくつかの計算を実行してから、それらをguiに送り返したいと思います。これはPyQtの範囲外ですか?私はそれが非常に自然な使用事例だと思うだろう。 – user1412286

+0

私が意味したのは、ケビン・クラマーが答えたところです。プロパティバインディングを使用して値をQML-Sideに取得する必要があります。したがって、Pythonを使ってQML-Sideに書き込むのではなく、QMLを使ってPython-Sideから読み込みます。 – derM

答えて

3

まず、PythonやC++側では、特に値ラベルの更新では行いません。あなたが同じことをするだろう総和ような些細な計算のためにあなたは、単にプロパティバインディングを使用する値ラベル、例えば:

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

については

計算がもっと複​​雑で、Python側で計算したいと思うなら、QML側ではシグナルは必要ありません。

代わりに、両方の引数をとるスロットを提供するPythonのQObject派生クラスを持つオプションがあります。

このオブジェクトのインスタンスは、setContextProperty() QMLエンジンのrootContext()メカニズムを介してQMLに公開されます。 各スピンボックス 'onValueChangedハンドラは、両方の値を持つこのスロットを呼び出すことができます。

結果として、スロットは値を返すか、オブジェクトがスロットによって更新され、QMLで結果ラベルのバインディングとして使用される結果プロパティを提供する可能性があります。

0

あなたがお勧めの方法で同じスロットに接続された2つの信号を持つことはできません。すべてのシグナルは、スロット内のコードを1回実行するようトリガーします。それはエレクトロニクスの物理的なワイヤーのような真の連続的な接続ではありません(あなたが想像しているかもしれないと思います)。

スピンボックスの値が変更された場合、スピンボックスの値(スピンボックス自体、ラベル、またはそれを保存した別の変数)を取得して追加する必要があります。例:

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()を何かに接続する必要はありません。前の2つのスロット関数によって直接呼び出されています。

+0

グローバル変数は、spin_sum()関数ではまだ "0"ですが、!そして、リターンは更新スロットの外で利用できるようには機能しません。これはまだ動作しません。あるいは、私はコーヒーを必要とするかもしれません。 – user1412286

+0

グローバル変数は実際には更新関数でグローバルに設定する必要があります。つまり、 'global spin1_global'です。しかし、好奇心の中で、スピンボックスからの値が直接使用される場所では、他の方法がどのように機能しますか?私はそれが元の質問だと思います。 – user1412286

+0

私は自分の答えを修正しましたが、現時点で実際にテストすることはできないため、マイナーなエラーが発生する可能性があります。 –

関連する問題