2016-04-05 7 views
7

私はPyQt5のいくつかのドキュメントを読んで、簡単なシグナルスロットメカニズムを考案しています。私は設計上の考慮のために休止した。PyQt emit()とpyqtSignal()の適切な使用

は、次のコードを考えてみましょう:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     #redundant connections 
     sld.valueChanged.connect(lcd.display) 
     sld.valueChanged.connect(self.printLabel) 
     sld.valueChanged.connect(self.logLabel) 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 


if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

は、スライダーに加えられた変更を追跡するために、私は単純に印刷して、変更内容を記録します。私がコードについて気に入らないのは、スロットに同じ情報を3つの異なるスロットに送信する必要があるということです。

整数を1つのスロット機能に送信する私自身のpyqtSignalを作成することは可能ですか?そして、順番に、スロット機能は変更が必要ですか?

  • それの目的のない良い例がPyQt Signal-Slot docsに存在しないのでたぶん私は完全にemit()の目的を理解していません。パラメータなしのemitを実装する方法の例です。

私がしたいのは、emit関数を処理する関数を作成することです。以下を考慮してください:

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal) 
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, 
    QVBoxLayout, QApplication) 


class Example(QWidget): 

    def __init__(self): 
     super().__init__() 

     #create signal 
     self.val_Changed = pyqtSignal(int, name='valChanged') 

     self.initUI() 

    def initUI(self): 

     lcd = QLCDNumber(self) 
     sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(lcd) 
     vbox.addWidget(sld) 

     self.setLayout(vbox) 

     sld.val_Changed.connect(self.handle_LCD) 
     self.val_Changed.emit() 

     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 
     self.show() 

    def handle_LCD(self, text): 
     '''log''' 
     print(text) 
     '''connect val_Changed to lcd.display''' 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

明らかに深刻な設計上の欠陥があります。私は関数呼び出しの順番を頭で囲むことはできません。そして私はpyqtSignalを正しく実装していません。しかし私は正しく、次の3点を明記することは、私は適切なアプリを作る助けになると信じています:

  1. を事前に定義された信号の場合:スロット機能に信号を送ります。信号値を使用するためにスロットを再実装することができます。
  2. pyqtSignalオブジェクトをいくつかのパラメータで生成します。これらのパラメーターの目的は何か、そしてそれらが '放出'パラメーターとどのように異なるかはまだ明確ではありません。
  3. emitは、特定の信号値をスロット機能に送るために再実装することができます。これまでの信号方法とは異なる値を送る必要がある理由はまだ明確ではありません。

いいスタイルの領域にあるかどうかはまだ分かっていないので、私がやろうとしていることを完全に自由に変更できます。

答えて

11

独自のスロット(任意のpython呼び出し可能)を定義して信号に接続し、その1つのスロットから他のスロットを呼び出すことができます。独自の信号を定義する場合

class Example(QWidget): 

    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def printLabel(self, str): 
     print(str) 

    def logLabel(self, str): 
     '''log to a file''' 
     pass 

    @QtCore.pyqtSlot(int) 
    def on_sld_valueChanged(self, value): 
     self.lcd.display(value) 
     self.printLabel(value) 
     self.logLabel(value) 

    def initUI(self): 

     self.lcd = QLCDNumber(self) 
     self.sld = QSlider(Qt.Horizontal, self) 

     vbox = QVBoxLayout() 
     vbox.addWidget(self.lcd) 
     vbox.addWidget(self.sld) 

     self.setLayout(vbox) 
     self.sld.valueChanged.connect(self.on_sld_valueChanged) 


     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Signal & slot') 

また、彼らはその上でD」pyqtSignalにクラス変数

class Example(QWidget): 
    my_signal = pyqtSignal(int) 

引数として定義されemitをされるオブジェクトのタイプを定義する必要がありますこの場合には、あなたが

self.my_signal.emit(1) 

を行うことができますので、信号は、EMITは、特定の信号VAを送信するために再実装することができますスロット のスロットにあいます。これまでの信号方法と異なる の値を送信する必要がある理由はまだ明確ではありません。

一般に、内蔵信号を放出してはいけません。あなたが定義したシグナルだけを放出する必要があります。シグナルを定義する際には、異なるタイプの異なるシグネチャを定義することができ、スロットはどのシグネチャを接続するかを選択できます。たとえば、あなたがこの

my_signal = pyqtSignal([int], [str]) 

は、これは、2つの異なるシグネチャで信号を定義します行うことができ、そしてスロットは実際には1

@pyqtSlot(int) 
def on_my_signal_int(self, value): 
    assert isinstance(value, int) 

@pyqtSlot(str) 
def on_my_signal_str(self, value): 
    assert isinstance(value, str) 

のいずれかに接続することができ、私はめったに信号署名をオーバーロードしません。私は通常、同じ信号に過負荷をかけるのではなく、異なる署名を持つ2つの別々の信号を作成します。しかし、Qtにはこのようなオーバーロードされたシグナルがあるので(例えば、QComboBox.currentIndexChanged)、存在し、PyQtでサポートされます。

+0

'@pyqtSlot(int) 'をコメントアウトしても出力には影響しません。これはなぜですか? – Max

+0

デコレータの真の目的は、あまりにも多くの目的を果たすことができるようです。 – Max

+0

これはオーバーロードのためだけではありません。この[回答](http://stackoverflow.com/a/14431607/1547004)ではかなりうまく説明されています。スレッド間で信号を送信する場合は、スロットデコレータも必要です。 –