Pyside6のシグナルとスロット

本記事では，pythonのGUI製作を行うライブラリであるPyside6のシグナルとスロットの説明を行います．
なにかアクションを行う際，例えば，ボタンを押した時にシグナルとスロットを用いて，メッセージの表示等の，指定した操作を行うことができます．

## シグナルとスロットの基本概念
**シグナル（Signal）:** シグナルは、特定のイベントが発生したことを他のオブジェクトに通知するための仕組みです。たとえば、ボタンがクリックされたときにシグナルを発することができます。シグナルは、関数呼び出しのように引数を持つことができ、その引数はスロットに渡されます。

**スロット（Slot）:** スロットは、シグナルを受け取って動作を実行する関数やメソッドです。シグナルが発行されると、接続されたスロットが呼び出されます。スロットは、通常の関数やメソッドであり、シグナルから渡された引数を受け取ることができます。

## 実際の動作のイメージ
Handlerクラスが Button クラスのシグナル clicked と接続されている場合、Button クラスの click メソッドが呼ばれると、clicked シグナルが発行されます。
clicked シグナルは、on_button_clicked スロットと接続されているため、このメソッドが呼び出され、message 引数としてシグナルから渡された文字列（例えば "Button was clicked!"）が print されます。図で書くと，下記のようになります．
![シグナルとスロット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457930/0a196918-ad59-1f84-0685-21988c374aaa.png)

これは，ボタンが押されると，メッセージを持ったシグナルが発行され，on_button_clickedメソッド（ただのメソッドだがここではスロットという呼び名）に，メッセージが渡され，printされます．



## シグナルとスロットの接続
シグナルとスロットは、通常以下の手順で接続されます。

**シグナルの定義**: クラス内でシグナルを定義します。
**スロットの定義**: シグナルを受け取る関数やメソッド（スロット）を定義します。
**接続**: シグナルとスロットを接続して、シグナルが発行されたときにスロットが呼び出されるようにします。

補足）接続には，Pyside6で用意されているSignalクラスのインスタンス（オブジェクト）の，clickedを使用します．また後でコードと共に詳しく説明します．


## ソースコードの全容
ここでは，イメージ図に示した通り，ボタンに関するシグナルとスロットを対象にして説明を行います．まず，コードの全体像です．この後，細かく分けて説明していきます．
``` python:python
from PySide6.QtCore import QObject, Signal, Slot

class Button(QObject):
    # 引数として文字列を取るシグナルを定義
    clicked = Signal(str)

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

    def click(self):
        # シグナルを発行し、文字列を引数として渡す
        self.clicked.emit("Button was clicked!")

class Handler(QObject):
    def __init__(self):
        super().__init__()

    @Slot(str)
    def on_button_clicked(self, message):
        print(message)

# オブジェクトの作成
button = Button()
handler = Handler()

# シグナルとスロットを接続
button.clicked.connect(handler.on_button_clicked)

# シグナルを発行してスロットを呼び出す
button.click()

```

## buttonクラス

``` python:python

class Button(QObject):
    # 引数として文字列を取るシグナルを定義
    clicked = Signal(str)

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

    def click(self):
        # シグナルを発行し、文字列を引数として渡す
        self.clicked.emit("Button was clicked!")

```

QObjectクラスを継承することで，Qtオブジェクトの基本的な機能を持ちます．ここでは，シグナルを定義，発行しています．
続いて，さらに細かく見ていきます．

```python 
clicked=Signal(str)
```
ここでは，clicked という名前のシグナルを定義しています。このシグナルは、str 型の引数を持つことができ、文字列を他のオブジェクトに渡すために使われます。Signal(str) によって、このシグナルは文字列を引数として受け取ることができることを明示しています。


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

これは，クラスのコンストラクタです。super().__init __() を呼び出すことで、QObject クラスの初期化を行います。この初期化により、Button クラスがQtオブジェクトとしての基本的な機能を持つことができます。

``` python
def click(self):
    self.clicked.emit("Button was clicked!")
```
こちらのclick メソッドは、ボタンがクリックされたときに呼び出されるメソッドです。
self.clicked.emit("Button was clicked!") は、clicked シグナルを発行する部分です。emit メソッドを使って、シグナルを発行し、指定した引数（この場合は "Button was clicked!" という文字列）をスロットに渡します。

## Handler クラス:Qtのシグナルとスロットのメカニズムに基づいて動作するクラス
``` python 
class Handler(QObject):
    def __init__(self):
        super().__init__()

    @Slot(str)
    def on_button_clicked(self, message):
        print(message)

```
ここでは、Handler クラスが、特定のシグナルが発行されたときにそのシグナルを受け取って処理を行うためのスロットを定義しています。

```python
class Handler(QObject):
```
この部分で、Handler クラスを定義しています。QObject を継承することで、このクラスもQtオブジェクトとしての機能を持ち、シグナルとスロットのメカニズムを利用できます。

```python
def __init__(self):
    super().__init__()
```
これはクラスのコンストラクタです。クラスのインスタンスが作成されたときに呼び出されます。
super().__init __() を呼び出して、親クラスである QObject の初期化を行います。これにより、Handler クラスが QObject としての基本的な機能を持つことが保証されます。

```python
@Slot(str)
def on_button_clicked(self, message):
    print(message)
```

この部分で、シグナルを受け取るスロットを定義しています。
**Slot(str) デコレータ**を使用して、このメソッドが**スロット**であり、str 型の引数を受け取ることを指定しています。スロットとは、シグナルを受け取るために定義された関数やメソッドのことです。
def on_button_clicked(self, message) は、シグナルが発行されたときに呼び出されるメソッドです。このメソッドは message という引数を受け取り、シグナルから渡されたメッセージを受け取ります。
print(message) というコードは、渡されたメッセージをコンソールに出力します。例えば、"Button was clicked!" というメッセージが渡された場合、それが画面に表示されます。

## シグナルとスロットの接続
最後に，上記で作成したシグナルとスロットのオブジェクトを作成し，Signalクラスのconnectメソッドを用いて，2つを接続します．

```python
# オブジェクトの作成
button = Button()
handler = Handler()

# シグナルとスロットを接続
button.clicked.connect(handler.on_button_clicked)

# シグナルを発行してスロットを呼び出す
button.click()
```

## まとめ
・シグナルは何かアクションがあった時に指定したメソッドへ指示を出すもの．橋渡しをするもの．
・スロットは，シグナルから受けた命令に従うただのメソッド

これを覚えていれば十分だと思います．