日本語 English 한국어

PySideのシグナルとスロット

このページではPySideのシグナルとスロットの使い方を説明します。いわゆる新スタイルのシグナルとスロットの使い方を中心に説明しますが、参考として旧スタイルの使い方も合わせて紹介します。

PyQtでは、新スタイルのシグナルとスロットはPyQt v4.5から導入されました。この新スタイルの目的は、PythonプログラマによりPythonicな構文を提供することです。PySideは PSEP 100 [pyside.org] をこの実装のガイドラインとして使用しています。

旧スタイルの方法 SIGNALとSLOT

QtCore.SIGNALQtCore.SLOT マクロは、Qtのシグナル/スロット配信機構とPythonをつなぐインタフェースであり、旧スタイルのシグナル/スロットの使い方です。

次の例ではQPushButtonの一般的なシグナルであるclickedシグナルを使用しています。旧スタイルではマクロ経由のシグナルと接続先のスロットをオブジェクトに伝えるため、connectメソッドはpythonに馴染みにくい構文になります。

  1. ...
  2.  
  3. def someFunc():
  4.     print "someFunc has been called!"
  5.  
  6. ...
  7.  
  8. button = QtGui.QPushButton("Call someFunc")
  9. QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), someFunc)
  10.  
  11. ...

新スタイルの方法 Signal()とSlot()

新スタイルでは新しい構文を使ってシグナルとスロットを接続します。先ほどの例は次のようにすっきりと書くことができます。

  1. ...
  2.  
  3. def someFunc():
  4.     print "someFunc has been called!"
  5.  
  6. button = QtGui.QPushButton("Call someFunc")
  7. button.clicked.connect(someFunc)
  8.  
  9. ...

QtCore.Signal()の使い方

シグナルは QtCore.Sginal() クラスを使って定義します。シグナルのパラメータとしてPythonとCの型が指定できます。オーバーロードをする場合は、複数のパラメータをタプルやリストを使って指定します。

またクラスはシグナル名を定義する名前付き引数(キーワード引数) name を持っています。キーワード name が未指定の場合、代入先の変数名がシグナル名になります。

以下の例題集で、 QtCore.Signal() の使用例をまとめています。

注:シグナルは QObject を継承したクラス内でのみ定義してください。これにより、シグナル情報がQMetaObjectクラスの構造体に追加されます。

QtCore.Slot()の使い方

スロットの指定やオーバーロードには QtCore.Slot() デコレータを使います。スロットのパラメータ定義は QtCore.Signal() と同じく型を指定します。ただしオーバーロードの場合、 Signal() クラスのようにタプルやリストによるパラメータ指定は行いません。代わりにパラメータ毎に新たなデコレータを定義します。以下の例題でこの違いが明確に分かると思います。

また、キーワード引数も異なります。 Slot()nameresult の2つのキーワード引数を受けとります。 result キーワードは返却型を定義し、CとPythonの型を指定できます。 name キーワードは Signal() と同様に、未指定の場合には関数名がスロット名になります。

例題集

以下の例では、PySideのシグナルとスロットの定義、および接続方法を示しています。基本的な例とより複雑な例を示します。

  • 次の例は、基本的なHello Worldプログラムです。パラメータを指定せずにシグナルとスロットを接続しています。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys
  5. from PySide import QtCore, QtGui
  6.  
  7. # スロットとして使用する関数を定義します
  8. def sayHello():
  9.     print 'Hello world!'
  10.  
  11. app = QtGui.QApplication(sys.argv)
  12.  
  13. button = QtGui.QPushButton('Say hello!')
  14.  
  15. # clickedシグナルとsayHelloスロットを接続します
  16. button.clicked.connect(sayHello)
  17. button.show()
  18.  
  19. sys.exit(app.exec_())

  • 次の例は、引数が追加されたHello Worldプログラムの修正版です。スロットに引数が追加され、さらに新しいシグナルが作成されています。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys
  5. from PySide import QtCore
  6.  
  7. # 新たなスロットを定義します。このスロットは文字列を受け取り
  8. # 名前が「saySomeWords」になります
  9. @QtCore.Slot(str)
  10. def saySomeWords(words):
  11.     print words
  12.  
  13. class Communicate(QtCore.QObject):
  14.     # シグナルをその場で作成し、名前を「speak」とします
  15.     speak = QtCore.Signal(str)
  16.  
  17. someone = Communicate()
  18. # シグナルとスロットを接続します
  19. someone.speak.connect(saySomeWords)
  20. # 「speak」シグナルを送出します
  21. someone.speak.emit("Hello everybody!")

  • 次はオーバーロードを行います。前回のプログラムを少し修正して、オーバーロードのデコレータを作ります。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys
  5. from PySide import QtCore
  6.  
  7. # Cの「int」とpythonの「str」型を受け取る新たなスロットを定義します
  8. # 名前は「saySomething」です
  9. @QtCore.Slot(int)
  10. @QtCore.Slot(str)
  11. def saySomething(stuff):
  12.     print stuff
  13.  
  14. class Communicate(QtCore.QObject):
  15.     # 2つの新しいシグナルをその場で作成します
  16.     # 「int」と「str」型を持つシグナルです
  17.     speakNumber = QtCore.Signal(int)
  18.     speakWord = QtCore.Signal(str)
  19.  
  20. someone = Communicate()
  21. # シグナルとスロットを接続します
  22. someone.speakNumber.connect(saySomething)
  23. someone.speakWord.connect(saySomething)
  24. # 2つの「speak」シグナルを送出します
  25. someone.speakNumber.emit(10)
  26. someone.speakWord.emit("Hello everybody!")

  • 最後の例では、スロットとシグナルをオーバーロードし、複雑な接続と送出を行います。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys
  5. from PySide import QtCore
  6.  
  7. # Cの「int」とpythonの「str」型を受け取る新たなスロットを定義します
  8. # 名前は「saySomething」です
  9. @QtCore.Slot(int)
  10. @QtCore.Slot(str)
  11. def saySomething(stuff):
  12.     print stuff
  13.  
  14. class Communicate(QtCore.QObject):
  15.     # オーバーロードのシグナルを作成します
  16.     # 「int」と「str」型の2つの型を持つシグナルです
  17.     speak = QtCore.Signal((int,), (str,))
  18.  
  19. someone = Communicate()
  20. # シグナルとスロットを接続します。シグナルはデフォルトでは「int」型になります
  21. # 「str」型にする場合には接続時に指定する必要があります
  22. someone.speak.connect(saySomething)
  23. someone.speak[str].connect(saySomething)
  24.  
  25. # 異なる型を持つ「speak」シグナルを送出します
  26. # デフォルトでは「int」型になり、「str」型を使う場合は明示的に指定します
  27. someone.speak.emit(10)
  28. someone.speak[str].emit("Hello everybody!")

PyQtとの互換性

PyQtの新スタイルとは、シグナル/スロット関数の命名規則が異なります。新スタイルのPyQtからPySideへの変換は、次のいずれかの方法で修正してください。

  1. from PySide.QtCore import Signal as pyqtSignal
  2. from PySide.QtCore import Slot as pyqtSlot

または次のようにします。

  1. QtCore.pyqtSignal = QtCore.Signal
  2. QtCore.pyqtSlot = QtCore.Slot

この修正によってpyqtSignal/pyqtSlotコールが、PySideのSignal/Slotコールに変換されます。

Categories: