2017-02-14 5 views
1

私は、JavaでcliベースのカスタムWebクローラーを開発しています。結果を表示するためのユーザーフレンドリーなグラフィカルインターフェイスが必要なので、いくつかのツリー、ラベル、テーブルなどを含むスイングフレームを追加する必要があります。 そのグラフィカルインターフェイスはそのスイッチの1つで、ユーザーがそれを呼び出す場合に備えて起動する必要があります。したがって、必要に応じてアプリケーションを他のタスクに進め、GUIフレーム内のコンポーネントを更新できるように、このインターフェイスを新しいスレッドで開始する必要があります。 私のGUIクラスはいくつかのことのようである:別のスレッドでスウィングを使用する

public class Frame extends JFrame { 
    ...... 
    public static JLabel urlLabel; 
    ...... 
    public static void run() { 
     urlLabel = new JLabel(); 
     urlLabel.setText("Test Url"); 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new Frame().setVisible(true); 
      } 
     }); 
    } 
    ..... 
} 

そして、私はこのように私のメインクラスからそれをfork:

..... 
if(cmd.gui){ 
    Frame.run(); 
    Frame.urlLabel.setText("New Url"); 
} 
...... 

残念ながら、ラベルのテキストは変更されません。私はすでにrepaint()revalidate()などの他の関数をテストしましたが、何も表示されませんでした。 私はgetText()をテストして、メインクラスからurlLabelにアクセスすることが可能であることを確認しました。それは働いていました(ラベルのテキストを取得できました)。

私はこの問題をどのように解決できるのでしょうか? (基本的には、別のスレッドでスイングフレームを開始し、そのコンポーネントをメインスレッドから制御する必要があります)

ありがとうございます。

+2

毎回、SwingUtilities.invokeLaterで既に行ったように、専用のスイングスレッドを使用してUI要素を変更するだけで済みます。あるいは、あなたの問題が間違っていると私は理解しています – xander

+0

@xander私はすでにそれをしました。スイングは新しい専用スレッドで開始され、そのコンポーネントを更新/変更する必要があります。私はそれがカスタムWebクローラーであると説明したので、アプリケーションがWebサイトをクロールしている間に、収集した新しいデータをGUIに追加する必要があります。 –

+0

@SinaYazdanmehrまた、スイングはスレッドセーフではなく、UIへのすべての更新はイベントディスパッチスレッドのコンテキスト内で行わなければならないことに注意してください。また、クロスオブジェクト通信メソッドとして '静的'に頼るべきではありません。それはコード内の単なる痛みです。代わりに、UIとコードの他の部分との間でモデルを共有する必要があります。 UIは、モデルが変更されたときにオブザーバーパターンを使用して更新を取得し、EDT内から 'invokeLater'を介して更新されるようにします。通常は、UI以外の部分を駆動するSwingWorkerを使用しますが、UIを通知することができるのは – MadProgrammer

答えて

0

invokeLater()を使用すると、このスレッドの現在の操作が完了した後に、RuntimeがEventThreadで開始されます。ラベルが更新されていない場合は、EventThreadが何か他の操作をしている可能性があります。ウェブをクロールする。

クロール作業が別のスレッドで行われていることを確認する必要があります(新しいスレッドを開始してください。これはおそらくEventThreadなので、実行するスレッドは使用しないでください)。次に、この別のスレッドでinvokeLater()を使用して、EventThreadのラベルを変更することができます。

ヒント:SwingUtilities.isEventDispatchThread()を使用してEventThreadにいるかどうかを確認できます。

データ/モデルは異なるスレッドで使用されるため、GUIが表示しようとしている間にワーカースレッドでデータが変更されると問題が発生する可能性があることに注意してください。

0

ありがとうございました。 最後に、SwingUtilities.invokeLaterを使ってラベルのテキストを更新することで、この障害を克服することができました。 他の誰かがそれを必要とするかもしれないので、私は、ここでのアプローチを言及:

メインクラス:

public class Frame extends JFrame { 
...... 
    private static JLabel urlLabel; 
...... 
    public JLabel getU(){ 
    return urlLabel; 
    } 
    public static void run() { 
    urlLabel = new JLabel(); 
    urlLabel.setText("Test Url"); 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      new Frame().setVisible(true); 
     } 
    }); 
} 
    ..... 
} 

GUIクラス:この方法に関する問題だけ

if(cmd.gui){ 
    Frame().run(); 
    SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       gui.getU().setText("New Url"); 
      } 
    }); 
} 
..... 

: ので、Iいくつかのラベルとツリーノードをクロール中に数回更新する必要があり、それぞれが新しいものを開始するのがわかると思ったのですが、それぞれが過負荷になるのでしょうか?はいの場合、どうすればそれを管理できますか?

--- UPDATEは---

は、@ザンダーさんのコメントによれば、Runnableの代わりにラムダを使用することが可能です。私はラムダは新しいオブジェクトほどオーバーロードがないと思う。

+0

1.ラムダは単なる組み込みメソッドなので、コードと本質的に同じですが、書き込み/読み込みはそれほど難しくありません。 2. UIを1つのSwingUtilities.invokeLaterコールに変更して組み合わせることができますが、必要に応じて何度も実行できる場合は、スイングUIスレッドでRunnableを同期させるだけです。 – xander

関連する問題