QTで始まる、パートII - シグナル、スロットとタイマー
この記事で私はQTで初心者のための小規模なチュートリアルを作るためにゲームに続いた。 今回は、独自のシグナルとスロットを作成する方法とタイマを処理する方法を示します。
ソースコードはこれで見つけることができますリンク 。
サンプルプログラムでは、クラスを使用しますタイマーで使いQTimer 、QTの主なクラスのいずれかを、クラスでのスタイル液晶ディスプレイの電卓を使用して、時間が表示されますQLCDNumberを 。
QTとタイマ
QTの中で最も基本的なサポートタイマーのメソッドを提供QObjectのクラスから利用可能ですstartTimer :: QObjectを() と QObject :: KillTimerを() 。 最初の方法は、一意のIDを返し、秒のタイマーは、このIDを使用してタイマーを終了します。
これが機能するためには、しかし、このメカニズムを使用するコード·スニペットは、 "イベントループ"内である必要があります。 瞬間からタイマーが時々からそれを開始されます(タイムアウト)アプリケーションdispateなりfireするとイベントが処理されるまで、プログラムの正常な流れを混乱させる。
タイムアウトの最大値が定義されていない、長年のタイムアウトのタイマーを作成できますが、最小の時間はシステムごとに異なります。 Linuxの2.6.xでは、これは(デフォルトは4 msです)は設定されている間、Windows Vistaで最小のタイマーは10ミリ秒です。 要求されたQTは、すべてのイベントを提供しようとしますが、システムが許可しない場合には、 "余剰"を破棄します。
タイマーは、スレッドで使用することもできますが、イベントループの内側であることの要件を満たす必要があります。 スレッドは、いつものように、別の記事に値する...
クラスの使いQTimerのタイマーは、一部の機能を可能にする、より高いレベルを実装します。 一つは、 使いQTimer :: singleShot()は、一度イベントを発生させます。
豊富なドキュメントと退屈な、繰り返しを読みますが、私を信じて、あなたはQDorDeCabecaの多くが保存されます...
シグナルとスロットの詳細
シグナルとスロットはオブジェクト、QTの基本的な部分の一つとの間の通信に使用されています。 イベントを処理するコールバックを実装するのではなく、このシステムでは、我々は、プログラミングをより直感的な意思、スロットへの信号接続の概念を使用します。
シグナルとスロットはによって処理されるクラスのメソッドであるメタオブジェクトコンパイラ(MOC)のソースコードがコンパイルされる前に。 彼らはの一部ではありません特別なステートメントを持っている標準C + +ではfazum mocは、ソースコードを解析し、コンパイルが生成されます。
あなたはシグナルとスロットを実装する任意のクラスにmocを実行すると、ソースコードの特定の量が生成されます。 プログラムを使用してqmakeを mocは、プログラムへの呼び出しは、プログラマにそれを透明に、Makefileによって負担されている。
クラスは、シグナルとスロットを実装することができ、それはへのアクセスを必要とするメタ-オブジェクトシステム 。 だからクラスから継承する必要がありますQObjectをとそのサブクラス、およびマクロが必要にQ_OBJECTお住まいの地域のプライバシーステートメントでは。 "[|保護されて|プライベート、パブリック]スロット"の準備を完了すると、信号はセクションとスロットのセクション"シグナル"で宣言されています。
宣言された後のスロットは、任意の他の一般的なメソッドとして定義され、明示的に他のと同様に呼び出すことができます。 すでに兆候がもう少し繊細であり、しかプログラマによって定義され、宣言されています。 その理由は? 構築する試みの終了時にこのメッセージ
TMP / moc_mydisplay.o:関数 `MyDisplay :: signalPlay() 'の場合: 〜/ストップウォッチを/ tmp / moc_mydisplay.cpp:89: `:: MyDisplayのsignalPlay()の複数の定義" TMP / mydisplay.o:〜/ストップウォッチ/ mydisplay.cpp:169:最初にここで定義されている collect2:ldはステータス1で終了を返し 行います。** [ストップウォッチ]エラー1
ファイル内に次のコードをmoc_mydisplay.cpp生成されます。
/ / 0信号 signalPlay ( ) ボイドMyDisplay :: signalPlay() { activate ( this , & staticMetaObject , 0 , 0 ) ; QMetaObject ::アクティブ(これは、&staticMetaObject、0、0); }
はい、mocはQTのいわゆるメタメソッドの定義の信号を生成します。 したがって、記号のボディを定義するCTで違法であるとresetメソッドは、コンパイルエラーを生成します。 mocはあなたのための信号の実装の世話をしてみましょう。
接続する
それはちょうどセットシグナルとスロットを使用している。 あなたは彼らがどのように相互作用するかを定義する必要があります。 これを行う方法はのこの相続人全体のconnect()メソッドを介してそれらを接続することである QObjectを 。 これは、mocはシグナルを実装しますので、そのコール(s)の結果への呼び出しスロット(S)は、同じパラメータを使用して、接続(S)。
最後のスロットがコールバックされるように、接続に応じて、信号があっても同じ値を返すことができます。 このため、複数のスロットに接続されている信号に対して非常に安全ではないことに注意して、何も呼び出しの順序を保証しません。
与えられた信号は、直接第二の信号に接続することができます。 ので、最初の信号にemit()を(その後放出するのと同じです)第二の信号で、MOCSを作成する工程の後、一方、最初の呼び出しの結果、他のメソッドに接続された呼び出しで結果番目の呼び出しに、と 。
接続する方法
そこにシグナルとスロットを接続するための3つの方法は、基本的には、正しく使用しないと発見することがとても困難なバグの原因となることがあります。 接続のこれらのフォームは、connect()メソッドに追加パラメータとして渡されます。 彼らは、次のとおりです。
接続を指示する :スロットは信号は、信号が発行されたスレッド内で発行された直後に呼ばれています。 これは、スロットへの直接コールとしての役割を果たします。
接続キューに入れられた :信号が送信され、スロットへの呼び出しは、QTの内部リストになり、信号が呼び出されるかが行われていないスロットに関わらず、すぐに返されます。 ループは、このリストを処理するeventeされ、それ以降でのみスロットは、オブジェクトがスロットに常駐するスレッド上で呼び出されます。
自動接続 :これは、接続のタイプを指定していないときに使用されるデフォルトのタイプです。 それの一つである"悪の種子"は、2つの異なる動作を示します:シグナルとスロットが同じスレッド上に存在する場合、直接接続として動作しますが、それ以外には、キュー内の接続で動作します。
キューに入れられた接続を遮断 :ヘイ! ちょうど3つではなかった? まあ、これはこの記事を読んで1つの利点である:あなたが矛盾してマニュアルを節約! この接続は、信号が正式に実行されるまで、シグナルスレッドがブロックされていることを除いて、キュー内の接続に似ています。 非常に慎重に使用すべきであることに注意してください、別のスレッドでシグナルとスロット。 誤用は、デッドロックを引き起こす可能性があります。 あなたはこのような何かを見たときのことがわかります。
ユーザ@ホスト:〜/ストップウォッチ$ /ストップウォッチ。 QT:BlockingQueuedConnectionを活性化している間に検出されたデッドロック:送信者は、 MyDisplay(0x8076ac0)である受信機QPushButton(0x807e2d8)
何を意味しているのかについての疑問を解決するには"オブジェクトが存在するスレッド" QT arespeitoのスレッドを参照してください。を。
常にシグナル、スロット、スレッドとタイマーと細心の注意を払う。 これらは、QTの主な特徴ですが、その誤用は見つけることが極めて困難なバグにつながる可能性があります。 それについてのすべてのドキュメントを参照してください。
ダウンソースへ
私たちの例では、2つのクラスとMyDisplayストップウォッチファイルとメイン一般的な構成です。 メインだけQApplicationオブジェクトストップウォッチを作成します。 クラスは、ボタンとLCDの表示スタイルを持つダイアログで構成されるプログラムのMyDisplay視覚的な部分の世話をする。 Stopwatchクラスは、タイマーを表示し、実装するためのウィジェットを作成します。 このアーキテクチャはクラスストップウォッチMyDisplayから継承することがさらに興味深いことに、ほとんどのelegenteないことに注意してください。 しかし、それは実質的にシグナルとスロットを使用する必要がなくなります。ゲームを台無しにするだろう
我々はオブジェクトが外部と通信するときにシグナルとスロットの使用が明確になります。 一般的に、クラスは外側の何か分からない。 それらの内の外部オブジェクトへのポインタを渡し、それがカプセル化が痛いとコードは以下の一般的なことができます。 この例では、シグナルとスロットを使用する方が興味深いのは、これは一般性やカプセル化で失われることなく、オブジェクト(内部ストップウォッチ)/からオブジェクトストップウオッチ(外部Mydisplay)へのレポートのイベントにmyDisplayです。
Qt Designerは(別の記事で私はそれをお話します)の助けを借りて、私は、ダイアログ、ボタンとLCDを作成しました。 した後は、我々の目的に合わせてコードを簡略化。 myDisplayはQDialogから継承され、これが間接的に十分なクラス宣言のprivateセクションにQ_OBJECTマクロを追加することでしたシグナルとスロットを使用するには、QObjectから継承する方法。 その後、他の補助の中で追加された方法:
公共スロット: long ) ; slotDisplayValueボイド(長い)。 プライベートスロット: slotPlayボイド(); slotStopボイド(); 信号: signalPlayボイド(); signalPauseボイド(); signalStopボイド(); signalResetボイド();
兆候は、ボタンのクリックに関連する外部のイベントに通信します。 公衆は、外部からのタイマ刻みの権利されている間、既に民間のスロットは、前処理の手順を行います。 したがって、このクラスは、外部に情報を送信し、他の側に何を知らなくても、外部から情報を受け取ります。 古き良きインターフェース契約を締結しました。
公共スロット: slotPlayボイド(); slotPauseボイド(); slotStopボイド(); slotResetボイド(); プライベートスロット: slotTickボイド(); 信号: long ) ; signalTicksボイド(長い)。
逆に、アナログとStopwatchクラスは、信号MyDisplayクラスを受けるスロットを実装し、そのスロット公衆に情報を送信する信号を宣言しています。
また、カウンタをインクリメント、10ミリ秒ごとに(私たちの友人がlerdinhos Vistaをフォローできるように!)起動されますQTimerを実装しています。 このカウンタは、表示形式や表示に送り返されます。
タイマーが停止、一時停止し、適切なボタンをクリックすると、いつでも再開できます。
Finalmentes
例自体は多くのコードはありませんが、タイマーとカスタムシグナルとスロットの構造の最も基本的な使用方法を示しています。 非常に特別な注意は、しかし、これらのリソースの使用を含む詳細に与えられるべきである、彼らは致命的なトラップになる可能性があります。
重要なリンク
シグナルとスロット
使いQTimer
QTのスレッド
QTのオンラインドキュメント
コメント
- Walison
- Walison
- Blabos
- Blabos
- ロドリゴ
- ロドリゴ
- ルーカス
- ルーカス
- http://blabos.pip.verisignlabs.com/ blabos
- http://blabos.pip.verisignlabs.com/ blabos
- ルーカス
- ルーカス

