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の型 を渡して、戻り値の型を定義することが出来ます。
nameSignal()と同じです。
もし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

これにより、pyqtSignalpyqtSlot の呼び出しは、
SignalSlot の呼び出しに変換されます。

クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 - 継承 2.1 日本 ライセンスの下に提供されています。