誰かが「シグナルとスロット」パターンを簡単に説明できますか?
6 に答える
シグナルとスロットは、送信者 (シグナル) と 0 個以上の受信者 (スロット) を分離する方法です。これらのイベントに関心のあるシステムの他の部分で利用できるようにしたいイベントを持つシステムがあるとします。イベントを生成するコードを、それらのイベントについて知りたいコードに配線するのではなく、シグナルとスロットのパターンを使用します。
送信側が (通常、そのイベント/シグナルに関連付けられた関数を呼び出すことによって) イベントを通知すると、そのイベントのすべての受信側が自動的に呼び出されます。これにより、プログラムの存続期間中、必要に応じてレシーバーを接続および切断できます。
この質問には C++ のタグが付けられていたため、Boost.Signalsライブラリへのリンクがあり、より詳細な説明があります。
シグナルとスロットは、オブザーバー パターンまたはパブリッシュ/サブスクライバー パターンの実装手段として考えられる場合に最もよく説明できると思います。signal
たとえばbuttonPressed(IdType)
、パブリッシャー側に1 つあります。ボタンが押されるたびに、その信号に接続されているすべてのスロットが呼び出されます。スロットは加入者側にあります。スロットは、たとえばsendMail(IdType)
.
イベント「ボタンが押されました」に加えて、IDが渡されているため、スロットはどのボタンが押されたかを認識します。IdType
パブリッシャーとサブスクライバーの間の接続を介して送信されるデータのタイプを表します。サブスクライバーが実行できる操作は、ボタンが押された場合にその特定のスロットが呼び出されるように、 に接続connect(signal, slot)
できることです。buttonPressed(IdType)
sendMail(IdType)
これの良いところは、サブスクライバー (スロット側) が信号の詳細を気にする必要がないことです。接続するだけです。したがって、ここには大量の疎結合があります。ボタンの実装は変更できますが、スロットのインターフェイスは同じままです。
詳細については、Qt Signals/SlotsまたはBoost Signalsを参照してください。
アプリケーションに GUI があると想像してください。ほとんどの場合、制御フローはあまり直線的ではありません。つまり、アクションの明確なシーケンスを持つ代わりに、GUI (ボタン、メニューなど) を操作するユーザーが必要になります。
これは基本的に、シグナルとスロットのパターンで非常にうまく実装できるイベント ドリブン モデルです。シグナルはオブジェクト (GUI コンポーネントと考えてください) によって生成されるイベントであり、スロットはそれらのイベントのレシーバーです。
以下に例を示します。プログラミング言語でオブジェクトとして表されるチェックボックスがあるとします。そのチェックボックスには複数のことが起こりえます。トグルすることができます。これは、設定または設定解除のいずれかであることも意味します。それらは、それが発することができる信号です。それらに、checkboxToggled、checkboxSet、checkboxUnset という名前を付けます。ご覧のとおり、この例では、チェックボックスはトグルされたときに常にcheckboxToggledシグナルを発行しますが、状態の変化に応じて、他の2つのシグナルのうちの1つも発行します。
ここで、他のオブジェクト、つまり、この例では常にオブジェクトとして存在しますが、「表示」および「非表示」できるラベルと、単純にビープ音を鳴らすことができるシステム ビープ音 (これもオブジェクトで表されます) があるとします。これらは、オブジェクトが持つスロットです。それらを「messageAppear」、「messageDisappear」、「beep」と呼びます。
チェックボックスが切り替えられるたびにシステムのビープ音を鳴らし、ユーザーがチェックボックスをオンまたはオフにしたかどうかに応じてラベルが表示または非表示になるようにするとします。
したがって、次の信号を次のスロット (左側の信号、右側のスロット) に接続します。
checkboxToggled -> beep
checkboxSet -> messageAppear
checkboxUnset -> messageDisappear
基本的にはそれだけです。
シグナルとスロットも引数を持つことができます。たとえば、数値を設定するスライダーを使用して、ユーザーがスライダーを移動するとすぐに、変更された値を発信された信号と共に送信したいとします:sliderChanged(int)。
もちろん、実際に何か役に立つことを行うには、独自のシグナルとスロットを含む独自のクラスを作成します。これは非常に簡単に行うことができ、独自のシグナルとスロットを使用すると、GUI やコードの他の部分とイベント ドリブンな方法で対話する優れた方法が得られます。
多くの場合、スロットに対応する信号が存在する可能性があるという意味で、信号とスロットは対称であることに注意してください。たとえば、チェックボックスはトグルされたときにシグナルを発する場合がありますが、チェックボックス自体をトグルするスロットを含む場合もあります。常に互いに反対に設定されている個別のチェックボックスを実装するのは簡単です。
QTのシグナルとスロットについて話していると思います。
とても簡単です。
クラスのインスタンスがシグナルを発生させることができ、おそらく別のクラスの別のインスタンスがそのシグナルをスロットでキャッチできます。関数を呼び出す人が、誰が呼び出しを受け取りたいかを知る必要がないということだけが、関数呼び出しのようなものです。
説明する最良の方法は、例を使用することです。
クラス QPushButton にはシグナル QPushButton::clicked() があります。その信号は、ボタンがクリックされるたびに発生します。プッシュ ボタンは、クリックが発生したことを知るために誰が興味を持っているかを知る必要はありません。信号を発するだけで、興味のある人は誰でもそれに接続できます。
ボタンが配置されている QDialog は、ボタンがいつクリックされたかを知りたいと思っています。スロット MyDialog::buttonClicked() があります。MyDialog c'tor では、信号が発生したときにスロットが呼び出されるように、ボタンの click() 信号をダイアログの buttonClicked() スロットに connect() する必要があります。
より高度なものの束:
- 引数、シグナルは引数を持つことができ、これらの引数はオプションでスロットにも渡すことができます。
- クロス スレッド呼び出し - クロス スレッドである必要があるシグナル スロット接続を作成している場合、QT は自動的にシグナルをバッファリングし、適切なスレッドにキューイングします。これは、たとえば、GUI スレッドが作業中のスレッドと通信する必要がある場合に自動的に発生します。