PySideにおけるシグナルとスロット
Signals_and_Slots_in_PySide | Qt Wiki | Qt Projectを勝手に翻訳したものです。
翻訳の誤りは保障しません(きっと誤りがあります)。
このページでは、PySideでのシグナルとスロットの使用法について説明します。
ここで主に説明するのは、新スタイルのシグナルとスロットと呼ばれる使用法ですが、
伝統的なスタイルも参考として示しておきます。
PyQtの新スタイルのシグナルとスロットは、PyQt v4.5で導入されました。
新スタイルの主たる目標は、Pythonプログラマに対し、よりPythonnicなシンタクスを提供することです。
PySideはその実装上のガイドラインとして、PSEP 100[pyside.org]を使用しています。 。
伝統的なシンタックス: SIGNAL と SLOT
QtCore.SIGNAL
マクロと QtCore.SLOT
マクロにより、
Pythonに、Qtへの シグナル・スロット 通知機構へのインターフェイスがあたえられます。
これは、シグナルとスロットを使う、古い方法です。
次の例では、QPushButton
のよく知られたシグナルを使っています。
connectメソッドのシンタックスはpythonフレンドリーではありません。
(マクロを通じて)シグナルに、そして接続対象のスロットに、オブジェクトを知らせなくてはなりません。
... def someFunc(): print "someFunc has been called!" ... button = QtGui.QPushButton("Call someFunc") QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), someFunc) ...
新しいシンタックス: Signal() と Slot()
新スタイルでは、シグナルやスロットを生成したり、接続したりする際に、新たなシンタックスを使用します。
先の例は次のように書き直すことが出来ます。
... def someFunc(): print "someFunc has been called!" button = QtGui.QPushButton("Call someFunc") button.clicked.connect(someFunc)
QtCore.Signal()を使う
シグナルは、QtCore.Signal()
classを使って定義できます。
パラメータとして、Pythonの型とCの型を渡すことが出来ます。
もし、オーバーロードする必要があるなら、型としてタプルやリストを渡せばよいです。
さらに、QtCore.Signal()
は、name
キーワード引数を受け取って、シグナル名を定義することが出来ます。もしnameが与えられなければ、新しいシグナルは、そのシグナルが代入される変数と同じ名前になります。
下の例の節には、QtCore.Signal()
の使いかたの例が並んでいます。
Note: QObject
を継承したクラス内でのみ、Signalは定義するべきです。
これにより、シグナルの情報がQMetaObject
に追加されます。
QtCore.Slot()を使う
スロットはQtCore.Slot()
デコレータを使って定義・オーバーロードできます。
Again, to define a signature just pass the types like the
QtCore.Signal()
クラスと同じように、シグニチャを定義するためには、シグニチャの型を渡せばよいです。
Signal()
クラスと違い、オーバーロードするときには、型のバリエーションのタプルやリストを渡すわけではありません。
代わりに、各シグニチャ毎に新しいデコレータで定義します。次の節を見れば明解になるでしょう。
もうひとつの違いは、キーワードです。Slot()
は nameとresultを浮けとります。
result
キーワードは、CやPythonの型 を渡して、戻り値の型を定義することが出来ます。
name
は Signal()
と同じです。
もしname
が与えられなければ、スロットの名前は、デコレータが使われた関数と同じ名前になります。
例
以下の例は、PySideではシグナルとスロットを、どのように定義し接続するか、
基本的な例から、もっと複雑なものまで、説明しています。
Hello World: 基本的な例です。シグナルを引数を取らないスロットに接続します。
#!/usr/bin/env python import sys from PySide import QtCore, QtGui # スロットとして使う関数を定義 def sayHello(): print 'Hello world!' app = QtGui.QApplication(sys.argv) button = QtGui.QPushButton('Say hello!') # clicked シグナルをsayHelloスロットに接続 button.clicked.connect(sayHello) button.show() sys.exit(app.exec_())
次に、引数を追加: Hello Worldを少し変更。引数がスロットに追加され、新しいシグナルが定義されています。
#!/usr/bin/env python import sys from PySide import QtCore # 'saySomeWords'という名前の、文字列を受け取る、新しいスロットを定義 @QtCore.Slot(str) def saySomeWords(words): print words class Communicate(QtCore.QObject): # create a new signal on the fly and name it 'speak' # 新しいシグナルをその場で定義して、'speak'という名前で付ける speak = QtCore.Signal(str) someone = Communicate() # シグナルとスロットを接続 someone.speak.connect(saySomeWords) # 'speak' シグナルを発信 someone.speak.emit("Hello everybody!")
オーバーロードを追加: 上の例を少し変更し、オーバーロードするデコレータが追加。
#!/usr/bin/env python import sys from PySide import QtCore # C の 'int' と 'str' を受け取る、'saySomething' という名前のスロットを定義 @QtCore.Slot(int) @QtCore.Slot(str) def saySomething(stuff): print stuff class Communicate(QtCore.QObject): # 新しいシグナルを2個その場で定義: # 一方はint型を扱い、もう一方は文字列を扱う speakNumber = QtCore.Signal(int) speakWord = QtCore.Signal(str) someone = Communicate() # シグナルとスロットを正しく接続 someone.speakNumber.connect(saySomething) someone.speakWord.connect(saySomething) # 各 'speak' シグナルを発信 someone.speakNumber.emit(10) someone.speakWord.emit("Hello everybody!")
スロットがオーバーロードされ、より複雑なシグナルへの接続・発信をする例
#!/usr/bin/env python import sys from PySide import QtCore # C の 'int' と 'str' を受け取る、'saySomething' という名前のスロットを定義 @QtCore.Slot(int) @QtCore.Slot(str) def saySomething(stuff): print stuff class Communicate(QtCore.QObject): # 新しいシグナルを2個その場で定義: # 一方はint型を扱い、もう一方は文字列型を扱う speak = QtCore.Signal((int,), (str,) ) someone = Communicate() # シグナルとスロットを接続する。 # デフォルト は'int' で、2つ目のシグナル接続には str を明示する必要がある。 someone.speak.connect(saySomething) someone.speak[str].connect(saySomething) # 'speak' シグナルを、異なる引数で発信 # デフォルト は 'int' で、str は 明示する必要がある。 someone.speak.emit(10) someone.speak[str].emit("Hello everybody!")
PyQtとの互換性
PyQtは、新しいシグナル/スロット用関数に、異なる命名規則を使っています。
この命名規則の新スタイルを使ったPyQtスクリプトPySideで動くようにするには,
以下に提示したどちらかの変更をすればよいです。
from PySide.QtCore import Signal as pyqtSignal from PySide.QtCore import Slot as pyqtSlot
あるいは
QtCore.pyqtSignal = QtCore.Signal QtCore.pyqtSlot = QtCore.Slot
これにより、pyqtSignal
と pyqtSlot
の呼び出しは、
Signal
と Slot
の呼び出しに変換されます。