2016-04-06 25 views
5

現在、pyqtSignal(int)とpyqtSlot(int)を生成するクラスを作成中です。難しいのは、特定の値を発する信号を作り出すことです。PyQt5シグナルスロットデコレータの例

私は次の簡単な例に似たものを作るにしたいと仮定します。上記のコードのための

import sys 
from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot) 
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) 

    @pyqtSlot(int) 
    def on_sld_valueChanged(self, value): 
     self.lcd.display(value) 
     self.printLabel(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') 
     self.show() 

if __name__ == '__main__': 

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

私の最初の質問は次のとおりです。

削除するときに、すべてのpyqtSlot()デコレータを使用する理由
  • pyqtSlot(int)はコードに影響しませんか?
  • 必要なときの例を挙げることはできますか?

は、特定の理由から、私はpyqtSignal()の工場を使用して独自の信号を生成したいとまともなドキュメントhereを与えられています。しかし、唯一の問題は、非常にsimple exampleが特定の信号を放出する方法の確固たる基盤を提供していないことです。ここで

は私がしようとしているものですが、自分が失っ発見した:

  1. QWidgetのサブクラスの多くの異なる種類の実装が可能になりますメタクラスを作成します。
  2. メタクラスは、クラス外から呼び出すことができる独自の信号を生成します。

これは私がつもりです:あなたが見ることができるように

from PyQt5.QtWidgets import QPushButton, QWidget 
from PyQt5.QtCore import pyqtSignal, pyqtSlot 
from PyQt5.QtWidgets import QSlider 

def template(Q_Type, name: str, *args): 
    class MyWidget(Q_Type): 

     def __init__(self) -> None: 
      super().__init__(*args) 
      self._name = name 

     def setSignal(self,type): 
      self.signal = pyqtSignal(type) 

     def callSignal(self): 
      pass 

    return MyWidget 

。私はこれを役に立つと思うのでウィジェットに名前を付けます。クラス内からQWidgetをインスタンス化してコードを単純化しようとします。

これは私が最初の例からウィジェットを生成するために、メインクラスをご希望の方法です:

  1. テンプレートメタクラス:

    import sys 
    from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot) 
    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) 
    
        @pyqtSlot(int) 
        def sld_valChanged(self, value): 
         self.lcd.display(value) 
         self.printLabel(value) 
    
        def initUI(self): 
    
         #instantiate the QWidgets through template class 
         self.lcd = template(QLCDNumber,'lcd_display') 
         self.sld = template(QSlider, 'slider', Qt.Horizontal) 
    
         #create signal 
         #self.sld.setSignal(int) 
    
         vbox = QVBoxLayout() 
         vbox.addWidget(self.lcd) 
         vbox.addWidget(self.sld) 
    
         self.setLayout(vbox) 
    
         #connect signal - this won't send the value of the slider 
         #self.sld.signal.connect(self.sld_valChanged) 
         self.sld.valueChanged.connect(self.sld_valChanged) 
    
         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_()) 
    

    ここで解決する必要がある唯一の2の問題があります間違って設定されていて、メタクラス内からQWidgetをインスタンス化できません。 Q_Typeは、そのタイプがPyQt5.QtWidgets.QSliderのときは、そのタイプがPyQt5.QtCore.pyqtWrapperTypeであることを教えています。

  2. テンプレート化されたクラスを使用してnewSignalを作成していますが、送信する変更された値を送信するには、どうすればQSliderを取得する必要がありますか。私はこれがemit()が遊びに来るが、それがどのように役に立つかについて十分な知識がないと信じています。 シグナルがスロット機能に値35を渡したい場合、私は関数呼び出しself.sld.emit(35)を作成することができます。どうやって問題になるのですか?

私は完全にオフベースであり、解決策を考え直しているかもしれません。自分の信号を修正して、自分の信号がスライダの値を放出できるようにしてください。

+1

なぜこのような醜い、複雑すぎる、そして難しいコードを書こうとしていますか?あなたが解決しようとしている実際の問題はありますか?私はあなたが誤って彼らが働くように設計されているのではなく、働くべきだと思うようにAPIを強制的に働かせようとしている、まったく共通の新人ミスをしています。これは[XY問題](http://xyproblem.info/)の変形です。 – ekhumoro

+1

@pyqtSignal()の使用は推奨されていません。 @pyqtSlot()のみを使用してください。マニュアルの使い方を調べてください。車輪を再構築しないでください。 (私に尋ねると、@ pyqtSlot()はPyQtの命名体系と一貫するために@pyQtSlot()という名前にする必要があります。 –

答えて

3

pyqtSlot(int)を除去するときに、なぜ全くpyqtSlot()デコレータを使用 は、コードには影響しませんか? が必要な場合の例を挙げることはできますか?

すでにprevious questionに記載されていますが、もう一度繰り返します。

PyQt4は が信号を接続する際にスロットとして使用される任意のPythonが呼び出し可能な可能にするが、それは明示的にQtのスロットであると のためにC++シグネチャを提供するよう Pythonの方法をマークすることが時々必要です。 PyQt4はこれを行うpyqtSlot()関数デコレータを提供します。

装飾されたPythonメソッドに信号を接続すると、 の方が、使用メモリ量が少なくて済むという利点もあります。あなたのprevious questionで対処としても

あなたはインスタンス変数などの信号を作成することはできません、彼らはクラスが属性でなければなりません。

これは

class MyWidget(QWidget): 
    signal = pyqtSignal(int) 

QWidgetのサブクラスの多くの異なる種類の実装が可能になりますメタクラスを作成しなければなりません

def setSignal(self,type): 
    self.signal = pyqtSignal(type) 

を働くことはありません。彼らはすでに、独自のメタクラスを使用するので

あなたは(これは信号魔法が動作することを可能にするものである)、QObjectsのためのメタクラスを定義することはできません。ただし、type機能を使用して、QObjectサブクラスファクトリを作成することはできます。

def factory(QClass, cls_name, signal_type): 
    return type(cls_name, (QClass,), {'signal': pyqtSignal(signal_type)}) 

MySlider = factory(QSlider, 'MySlider', int) 
self.sld = MySlider(Qt.Horizontal) 
self.sld.signal.connect(self.on_signal) 

メタクラスは、クラスの外から呼び出すことができ、独自の信号を生成してもらいます。

要するに、これを行わないでください。あなたはクラス外からの信号を放出すべきではありません。上記のファクトリの例はあまり有用ではありません。それらのクラスでカスタムメソッドを定義していないからです。通常、これはカスタム信号を利用する方法です

class MyWidget(QWidget): 
    colorChanged = pyqtSignal() 

    def setColor(self, color): 
     self._color = color 
     self.colorChanged.emit() 


class ParentWidget(QWidget): 

    def __init__(self): 
     ... 
     self.my_widget = MyWidget(self) 
     self.my_widget.colorChanged.connect(self.on_colorChanged) 
     # This will cause the colorChanged signal to be emitted, calling on_colorChanged 
     self.my_widget.setColor(Qt.blue) 

    def on_colorChanged(self): 
     # do stuff 
+0

私の質問は、コードを整理する方法、特に多くのウィジェットを扱う場合です。単純に1つのメインクラスに多数のウィジェットを置くのは賢明ではないようです。 – Max

+0

典型的なアプリケーションには、数多くのウィジェットがあり、すべて1つのウィンドウまたはダイアログに含まれています。そこには何も駄目なことはありません。正式なQtとPySideのサンプルアプリケーションを見てください。彼らはあなたにアプリケーションの編成方法を知らせます。 –

+0

色の変更をファイルに記録するとします。 (私がしたいのは、すべてのウィジェットのすべての信号をログに記録し、外部のフレームワークを呼び出すことです)。したがって、私は 'setColor'の中でログ機能を呼び出すことができますが、' colorChanged'を 'on_colorChanged'に渡す必要がある他のフレームワークから関数を呼び出すことができます。 – Max

関連する問題