4

スイングでパッシブ ビューベースの GUI システムを実装しようとしています。基本的に、ビューの実装 (実際にスイング コードを含む部分) を最小限に抑え、Presenter クラスでほとんどの作業を行いたいと考えています。プレゼンターはスイングに依存してはならず、「ショーを実行」する必要があります。つまり、ビューに何をすべきかを伝え、その逆ではありません。

長時間実行されるタスクや、一般的なスレッドの分離を処理するときに問題が発生します。GUI の更新を EDT で実行し、プレゼンター ロジックを別のスレッドで実行する必要があります。プレゼンターに GUI の一部を更新してもらいたい場合は、非常に簡単です。次のように記述します。

public interface View {
    void setText(String text);
}

public class Presenter {
    View view;
    ...
    public void setTextInVIew() {
        view.setText("abc");
    }
}

public class MyFrame implements View {
    JTextField textField;
    ...
    public void setText(final String text) {
        SwingUtilities.InvokeLater(new Runnable() {
            public void run() {
                textField.setText(text);
            }
        });
    }
}

ただし、何らかのアクションが発生したことを GUI がプレゼンターに通知する場合は、EDT から切り替えて、別のスレッドでそれに反応したいと考えています。

public class Presenter {
    ...
    public void buttonPressed() {
         // shouldn't run on EDT
    }
}

public class MyFrame implements View {
    JButton button;
    public MyFrame() {
        ...
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                presenter.ButtonPressed();
            }
        });
    }
}

actionPerformed コードは EDT から実行されているため、presenter.buttonPressed も同様です。スイングには SwingWorker の概念があることを知っています-別のスレッドでタスクを実行しますが、プレゼンターにスイングコードを挿入する必要があり、ビューがショーを実行しているようです。これを解決する方法はありますか?

4

4 に答える 4

2

次のようなことを行うことができます。これにより、GUIコードが所定の位置に保持され、EDTから抜け出すための作業が実行されます。

 button.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
           SwingWorker sw = new SwingWorker() {
             public Object doInBackground(){
                 presenter.ButtonPressed();             
                 return null;
            }
          }; 
          sw.execute();
        }
    });
于 2010-02-26T13:24:54.347 に答える
2

すべての定型文を回避するために、タスクAPIに関心があるかもしれません。それ以外の場合、akfのソリューションは問題ないように見えます(SwingWorkerの変数を作成する必要はありませんが、新しい変数を作成して匿名で実行することができます)。

于 2010-02-26T13:58:03.157 に答える
0

OK - 別のオプションがあります: スピン

最終的に、これらのソリューションはすべて、スレッド間の呼び出しをプロキシしています。目標は、ボイラープレート コードの山を必要としないソリューションを見つけることだと思います。たとえば、すべてのリスナーを配線して、適切なワーカー スレッド上にあるかどうかを確認し、そうでない場合は ExecutorService にプロキシすることができます。しかし、それは大きな問題です。ビジネス オブジェクトとビュー オブジェクトの間のレイヤー (バインディング/リスナー/レイヤーと呼びたいもの) でプロキシを実行する方がはるかに優れています。

于 2010-02-28T04:56:12.333 に答える
0

他の人が概説した SwingWorker ソリューションへの別のアプローチは、スレッド アフィニティを備えたイベント バスを使用することです。私は実際に、これがあなたがしようとしているデカップリングのタイプにとって最良の選択肢かもしれないと思っています.

チェックアウト: EventBus

バス アーキテクチャの実装は他にもありますが、EventBus が一般的です。

- アップデート -

そのため、EventBus は、非 EDT から EDT へのプロキシの非常にクリーンな方法を提供します (SwingUtilities.invokeLater() への大量の明示的な呼び出しよりもはるかに優れていますが、基本的には同じことを行います。EventBus は多くの通知を送信し、それらを単一の EDT ランナブルでヒットさせると、パフォーマンスが向上します)。

しかし、これは、EDT からのイベントをプロキシしてワーカー スレッドで実行する必要性に対応していません。EventBus には ThreadSafeEventService クラスがあり、おそらくそのようなビーストの基盤として使用できます。たとえば、ExecutorService と組み合わせて、特定のリスナーの特定のイベント登録を処理できます。

私にとってこれらすべての鍵は、あなたが思いついた解決策が何であれ、EDTのオン/オフのスピンをカプセル化しようとすることだと思います

ところで-ここで質問しているのは、Microsoftのアパートメントスレッドモデルに非常に似ています。

于 2010-02-27T05:31:06.083 に答える