スイングワーカースレッドモードを使用します
スイング開発者が並行性を慎重に使用することは非常に重要です。優れたスイングプログラムは、同時実行メカニズムを使用して、応答を失わないユーザーインターフェイスを作成します - どのような種類のユーザーインタラクションであっても、プログラムはいつでも応答できます。レスポンシブプログラムを作成するには、開発者はスイングフレームワークでマルチスレッドの使用方法を学ぶ必要があります。
スイング開発者は、次の種類のスレッドを扱います。
(1)初期スレッド、そのようなスレッドは初期化アプリケーションコードを実行します。
(2)イベントディスパッチスレッド、すべてのイベント処理コードはここで実行されます。スイングフレームワークと対話するほとんどのコードもこのスレッドを実行する必要があります。
(3)バックグラウンドスレッドとも呼ばれるワーカースレッドは、すべての時間のかかるタスクを実行します。
開発者は、これらのスレッドをコードで明示的に作成する必要はありません。ランタイムまたはスイングフレームワークによって提供されます。開発者の仕事は、これらのスレッドを使用して、レスポンシブで永続的なスイングプログラムを作成することです。
Javaプラットフォームで実行されている他のすべてのプログラムと同様に、スイングプログラムは追加のスレッドとスレッドプールを作成できます。これには、この記事で紹介されるアプローチの使用が必要です。この記事では、上記の3つのスレッドを紹介します。ワーカースレッドの議論には、javax.swing.swingworkerクラスの使用が含まれます。このクラスには、ワーカースレッドタスクと他のスレッドタスク間のコミュニケーションやコラボレーションなど、多くの有用な機能があります。
1。初期スレッド
各プログラムは、アプリケーションロジックの先頭に一連のスレッドを生成します。標準プログラムでは、そのようなスレッドは1つだけです。このスレッドは、プログラムのメインクラスのメインメソッドを呼び出します。アプレットでは、初期スレッドはアプレットオブジェクトのコンストラクターであり、initメソッドを呼び出します。これらのアクションは、Javaプラットフォームの特定の実装に応じて、1つのスレッド、または2つまたは3つの異なるスレッドで実行される場合があります。この記事では、このタイプのスレッド初期スレッドを呼び出します。
スイングプログラムでは、最初のスレッドではあまりやることはありません。彼らの最も基本的なタスクは、GUIを初期化し、イベントディスパッチスレッドでイベントを実行するために使用されるオブジェクトを調整する実行可能なオブジェクトを作成することです。 GUIが作成されると、プログラムは主にGUIイベントによって駆動され、それぞれがイベントディスパッチスレッドでイベントの実行を引き起こします。プログラムコードは、イベント駆動型のスレッドに追加のタスクを調整することができます(イベントの処理を妨げないように迅速に実行されます)、またはワーカースレッド(時間のかかるタスクの実行に使用)を作成します。
初期スレッドオーケストレーションGUI作成タスクは、javax.swing.swingutilities.invokelaterまたはjavax.swing.swingutilities.invokeandwaitに電話することです。どちらの方法でも、一意のパラメーターを取ります。Runnableは、新しいタスクを定義するために使用されます。それらの唯一の違いは次のとおりです。InvokerLaterはタスクのみを組織して返すことです。 InvokeandWaitは、返却する前にタスクが実行されるのを待ちます。
次の例を参照してください。
swingutilities.invokelater(new runnable()){public void run(){createandshowgui(); }}アプレットでは、GUIを作成するタスクをinitメソッドに入れて、invokeandwaitを使用する必要があります。それ以外の場合、GUIが作成される前に初期プロセスが可能になり、問題を引き起こす可能性があります。それ以外の場合、オーケストレーションGUI作成タスクは通常、最初のスレッドの最後のタスクであるため、両方ともInvokElaterまたはInvokeanDWaitを使用します。
なぜ最初のスレッドがGUIを直接作成しないのですか?スイングコンポーネントを作成および対話するために使用されるほぼすべてのコードは、イベントディスパッチスレッドで実行する必要があるためです。この制約については、以下で説明します。
2。イベント配布スレッド
スイングイベントの処理コードは、イベントディスパッチスレッドと呼ばれる特別なスレッドで実行されます。スイングメソッドを呼び出すコードのほとんどは、このスレッドで実行されます。これは、ほとんどのスイングオブジェクトが「非スレッドセーフ」であるため、必要です。
コードの実行は、イベントディスパッチスレッドで一連の短いタスクを実行すると考えることができます。ほとんどのタスクは、ActionListener.actionPerformedなどのイベント処理方法によって呼び出されます。残りのタスクは、InvokElaterまたはInvokeandWaitを使用して、プログラムコードによって調整されます。イベントディスパッチスレッドのタスクを迅速に実行できる必要があります。それ以外の場合、未処理のイベントがバックログされ、ユーザーインターフェイスが「レスポンシブ」になります。
イベントディスパッチスレッドでコードが実行されているかどうかを判断する必要がある場合は、javax.swing.swingutilities.iseventdispatchthreadに電話してください。
3。ワーカースレッドとスイングワーカー
スイングプログラムが長いタスクを実行する必要がある場合、通常はワーカースレッドを使用して行われます。各タスクは、javax.swing.swingworkerクラスのインスタンスであるワーカースレッドで実行されます。 SwingWorkerクラスは抽象クラスです。スイングワーカーオブジェクトを作成するには、サブクラスを定義する必要があります。通常、これを行うために匿名の内部クラスを使用します。
SwingWorkerは、コミュニケーションと制御機能を提供します。
(1)スイングワーカーのサブクラスは、完了したメソッドを定義できます。バックグラウンドタスクが完了すると、イベントディスパッチスレッドによって自動的に呼び出されます。
(2)SwingWorkerクラスはJava.util.concurrent.futureを実装します。このインターフェイスにより、バックグラウンドタスクは他のスレッドに戻り値を提供できます。このインターフェイスのメソッドは、バックグラウンドタスクの取り消しを可能にし、バックグラウンドタスクが完了または取り消されたかどうかを判断する機能も提供します。
(3)バックグラウンドタスクは、SwingWorker.publishを呼び出すことにより中間結果を提供でき、イベントディスパッチスレッドはこの方法を呼び出します。
(4)バックグラウンドタスクは、結合特性を定義できます。バインディング属性の変更によりイベントがトリガーされ、イベントディスパッチスレッドがイベントハンドラーを呼び出して、これらのトリガーイベントを処理します。
4.単純なバックエンドタスク
例は、このタスクは非常に簡単ですが、潜在的に時間がかかるタスクです。 TumbleItemアプレットは、一連の画像ファイルをインポートします。これらの画像ファイルが最初のスレッドからインポートされている場合、GUIが表示される前に遅延があります。これらの画像ファイルがイベントディスパッチスレッドにインポートされている場合、GUIは一時的に応答しない場合があります。
これらの問題を解決するために、TumbleItemクラスは、初期化されたときにStringWorkerクラスのインスタンスを作成および実行します。このオブジェクトのdoinbackgroundメソッドは、ワーカースレッドで実行され、画像をImageiconアレイにインポートし、その参照を返します。次に、DONEメソッドはイベントディスパッチスレッドで実行され、返された参照を取得し、アプレットクラスのメンバー変数IMGSに入れます。これを行うことで、画像のインポートが完了するのを待たずに、TumbleItemクラスがすぐにGUIを作成できます。
次のサンプルコードは、スイングワーカーオブジェクトを定義および実装します。
SwingWorker Worker = new SwingWorker <ImageIcon []、void>(){@Override public ImageIcon [] doinbackground(){final imageicon [] innerimgs = new Imageicon [nimgs]; for(int i = 0; i <nimgs; i ++){innerimgs [i] = loadimage(i+1); } innerimgsを返します。 } @Override public void done(){//「ロード画像」ラベルを削除します。 Animator.RemoveAll(); loopslot = -1; try {imgs = get(); } catch(arturtedexception Inignore){} catch(java.util.concurrent.executionexception e){string why = null;スロー可能な原因= e.getCause(); if(courd!= null){why = cound.getMessage(); } else {why = e.getmessage(); } system.err.println( "エラー取得ファイル:" +理由); }}}};スイングワーカーから継承されたすべてのサブクラスは、doinbackgroundを実装する必要があります。実行方法の実装はオプションです。
SwingWorkerは、2つのパラメーターを持つパラダイムクラスであることに注意してください。最初のタイプパラメーターは、doinbackgroundのリターンタイプを指定します。また、Doinbackgroundから戻り値を取得するために他のスレッドで呼び出すことができるGETメソッドの一種でもあります。 2番目のタイプパラメーターは、中間結果のタイプを指定します。この例は中間結果を返さないため、無効に設定されています。
GETメソッドを使用して、イベントディスパッチスレッドで使用されるオブジェクトIMG(ワーカースレッドで作成)を参照することができます。これにより、スレッド間でオブジェクトを共有できます。
実際には、オブジェクトをDoinbackgroundクラスによって返される方法は2つあります。
(1)SwingWorker.getを呼び出すパラメーターはありません。バックグラウンドタスクが完了していない場合、GETメソッドが完了するまでブロックされます。
(2)パラメーターを使用してSwingWorker.getを呼び出してタイムアウトを指定します。バックグラウンドタスクが完了していない場合は、完了するまでブロックします - タイムアウトの有効期限が切れない限り、その場合はjava.util.concurrent.timeoutexceptionを投げます。
5。中間結果のタスク
作業バックエンドタスクを中間結果を提供することは便利です。バックエンドタスクは、SwingWorker.publishメソッドを呼び出してこれを行うことができます。この方法は、多くのパラメーターを受け入れます。各パラメーターは、スイングワーカーの2番目のタイプパラメーターで指定されている必要があります。
SwingWorker.Processをオーバーライドして、パブリッシュメソッドによって提供される結果を保存できます。この方法は、イベントディスパッチスレッドによって呼び出されます。パブリッシュメソッドからの結果セットは、通常、プロセスメソッドによって収集されます。
filpper.javaが提供する例を見てみましょう。このプログラムは、バックグラウンドタスクを介して一連のランダムブールテストjava.util.randomを生成します。それはコインスローの実験のようなものです。結果を報告するために、バックグラウンドタスクはオブジェクトFlippairを使用します。
プライベート静的クラスFlippair {プライベートファイナルロングヘッド、合計; Flippair(長い頭、長い合計){this.heads = heads; this.otal =合計; }}ヘッドは真の結果を表します。合計は、スローの総数を表します。
バックグラウンドプログラムは、Filptaskのインスタンスです。
プライベートクラスのfliptaskはスイングワーカーを拡張します<void、flippair> {
タスクは最終結果を返さないため、最初のタイプパラメーターが何であるかを指定する必要はありません。それぞれの「スロー」の後、タスクは公開します:
@OverrideProtected void doinbackground(){long heads = 0;長い合計= 0; RANDOM RANDOM = new Random(); while(!iscancelled()){total ++; if(random.nextboolean()){heads ++; } publish(new Flippair(Heads、Total)); } nullを返します;}パブリッシュはしばしば呼び出されるため、イベントディスパッチスレッドによってプロセスメソッドが呼び出される前に、多くのフリッペア値が収集されます。このプロセスは、毎回返される値の最後のセットにのみ焦点を当て、それを使用してGUIを更新します。
保護されたボイドプロセス(リストペア){flippairペア= pairs.get(pairs.size() - 1); headstext.settext(string.format( "%d"、pair.heads)); TotalText.settext(string.format( "%d"、pair.total)); devtext.settext(string.format( "%。10g"、((double)pair.heads)/((double)pair.total)-0.5);} 6.背景タスクをキャンセルします
swingworker.cancelを呼び出して、実行するバックグラウンドタスクをキャンセルします。タスクは、独自の元に戻すメカニズムと一致する必要があります。これを行うには2つの方法があります。
(1)割り込みを受信すると、終了します。
(2)swingworker.iscenceledに電話します。スイングワーカーがCANCELを呼び出す場合、メソッドはtrueを返します。
7。属性と状態方法をバインドします
SwingWorkerはバウンドプロパティをサポートします。これは、他のスレッドと通信するときに非常に便利です。進捗状況と状態の2つの結合特性を提供します。進行状況と状態を使用して、イベントディスパッチスレッドのイベント処理タスクをトリガーできます。
プロパティ変更リスナーを実装することにより、プログラムは進行状況、状態、またはその他の拘束力のあるプロパティの変更をキャッチできます。
7.1 Progress Bound変数
Progress Binding変数は、0〜100の範囲の整数変数です。セッター(保護されたSwingWorker.setProgress)およびGetter(Public SwingWorker.getProgress)メソッドを事前に定義しました。
7.2状態境界変数
状態結合変数の変化は、ライフサイクル中にスイングワーカーオブジェクトを変更するプロセスを反映しています。この変数には、列挙タイプのSwingWorker.StateValueが含まれています。考えられる値は次のとおりです。
(1)保留中
この状態は、オブジェクトの作成から、doinbackgroundメソッドが呼び出されていることを知るためにしばらく続きます。
(2)開始
この状態は、DOINBackgroundメソッドが呼び出されるまで、しばらく続きます。
(3)完了
オブジェクトが存在する残りの時間は、この状態に残ります。
現在の状態の値を返す必要がある場合は、SwingWorker.getStateに電話することができます。
7.3Statusメソッド
将来のインターフェイスによって提供される2つの方法は、バックグラウンドタスクのステータスを報告することもできます。タスクがキャンセルされた場合、IsCancelledは真実です。さらに、タスクが完了した場合、つまり正常に完了するか、キャンセルされている場合、ISDONEはtrueを返します。
トップレベルのコンテナを使用します
Swingは、JFrame、Jdialog、Jappletの3つのトップレベルコンテナクラスを提供します。これらの3つのクラスを使用する場合、次のポイントに注意する必要があります。
(1)。画面に表示されるには、各GUIコンポーネントが含まれる階層の一部でなければなりません。包含階層はコンポーネントのツリー構造であり、トップレベルのコンテナはそのルートです。
(2)。各GUIコンポーネントは1回しか含めることができません。コンポーネントがすでに容器に入っていて、新しい容器に追加しようとすると、コンポーネントが最初の容器から取り外され、2番目の容器に追加されます。
(3)。各トップレベルのコンテナにはコンテンツペインがあります。一般に、このコンテンツパネルには、トップレベルのコンテナGUIのすべての視覚コンポーネントが(直接的または間接的に)含まれます。
(4)。上部のコンテナにメニューバーを追加できます。通常、このメニューバーは上部コンテナに配置されますが、コンテンツパネルの外側に配置されます。
1。トップレベルのコンテナと包含階層
スイングコンポーネントを使用する各プログラムには、少なくとも1つのトップレベルコンテナがあります。このトップレベルのコンテナは、階層を含むルートノードです。この階層には、このトップレベルのコンテナに表示されるすべてのスイングコンポーネントが含まれます。
通常、個別のスイングGUIベースのアプリケーションには、少なくとも1つのインクルージョン階層があり、そのルートノードはJFrameです。たとえば、アプリケーションに1つのウィンドウと2つのダイアログボックスがある場合、アプリケーションには3つのインクルージョンレベルがあります。つまり、3つのトップレベルコンテナがあります。封じ込め階層はJFRAMEをルートノードとして取得し、他の2つの封じ込め階層にはそれぞれルートノードとしてJDialogがあります。
スイングコンポーネントに基づくアプレットには、少なくとも1つのインクルージョン階層が含まれており、そのうちの1つをルートノードとしてJappletで作成する必要があると判断できます。たとえば、ダイアログボックスを備えたアプレットでは、2つの包含レベルがあります。ブラウザウィンドウのコンポーネントは封じ込め階層に配置され、そのルートノードはjappletオブジェクトです。ダイアログボックスには階層が含まれ、そのルートノードはJDialogオブジェクトです。
2.コンテンツパネルにコンポーネントを追加します
次のコード操作は、上記の例でフレームのコンテンツパネルを取得し、黄色のラベルを追加することです。
frame.getContentPane()。add(yellowlabel、borderlayout.center);
コードに示すように、最初にトップレベルのコンテナのコンテンツパネルを見つけて、メソッドgetContentPaneを介して実装する必要があります。デフォルトのコンテンツパネルは、パネルマネージャーとしてborderlayoutを使用して、JComponentから継承する単純な中間コンテナです。
コンテンツパネルのカスタマイズは簡単です - パネルマネージャーをセットアップするか、境界を追加します。ここでは、getContentPaneメソッドはJCOMPonentオブジェクトではなくコンテナオブジェクトを返すことに注意する必要があります。つまり、JComponentの機能の一部を利用する必要がある場合は、返品値を変換するか、コンテンツパネルとして独自のコンポーネントを作成する必要があります。私たちの例は通常、2番目の方法を使用します。 2番目の方法はより明確かつ明確であるためです。時々使用する別の方法は、コンテンツパネルを完全にカバーするために、コンテンツパネルに自己定義のコンポーネントを単に追加することです。
独自のコンテンツパネルを作成する場合は、それが不透明であることを確認するように注意してください。不透明なjpanelが良い選択です。デフォルトでは、JPanelのレイアウトはFlowLayoutとして管理されており、別のレイアウトマネージャーに置き換えることができることに注意してください。
コンポーネントがコンテンツパネルになるには、トップレベルコンテナのSetContentPaneメソッドを使用する必要があります。
//パネルを作成してコンポーネントを追加します。JPanelContentSpane= new jPanel(new borderlayout()); contentspane.setborder(someborder); contentspane.add(somecomponent、borderlayout.center); contentspane.add(anothercomponent、borderlayout.page_end); pane.//contentpane.setopaque(true); toplevelcontainer.setContentPane(ContentPane);
注:JSCrollpane、JSplitPane、JTabbedeBedPaneなどのコンテンツパネルとして透明なコンテナを使用しないでください。透明なコンテンツパネルは、コンポーネントを混乱させます。セットパーク(真)メソッドを介して透明なスイングコンポーネント不透明を作ることはできますが、一部のコンポーネントが完全に不透明に設定されている場合、それは正しく見えません。たとえば、タグパネル。
3.メニューバーの追加
理論的には、各トップレベルのコンテナにはメニューバーがあります。しかし、事実は、メニューバーがフレームまたはアプレットにのみ表示されることを示しています。トップレベルのコンテナにメニューバーを追加するには、jmenubarオブジェクトを作成し、メニューを組み立ててから、setJmenubarメソッドを呼び出す必要があります。 Topleveldemoインスタンスは、次のコードを介してメニューバーをフレームに追加します。
frame.setjmenubar(cyanmenubar);
4。ルートペイン
各トップレベルの容器は、ルートコンテナと呼ばれる暗黙の中間容器に依存しています。このルートコンテナは、コンテンツパネルとメニューバーを管理し、2つ以上の他のコンテナ(階層化されたペインなどを参照)を管理します。通常、スイングコンポーネントルートコンテナの使用について知る必要はありません。ただし、マウスのクリックをインターセプトしたり、複数のコンポーネントを描画したりする場合は、ルートコンテナを知る必要があります。
上記は、コンテンツパネルとオプションのメニューバーについて説明されており、ここでは繰り返されません。ルート容器に含まれる他の2つのコンポーネントは、レイアウトパネルとガラスパネルです。レイアウトパネルには、メニューパネルとコンテンツパネルが直接含まれており、Z座標で追加された他のコンポーネントをソートできます。通常、ガラスパネルは、最上層で発生するアクションアクションを傍受するために使用され、複数のコンポーネントを描画するためにも使用できます。