- ベストアンサー
Javaにおけるイベント処理の王道とは?
- Javaにおけるイベント処理の王道とは、GUIアプリケーションで複数のGUI部品の更新を行う方法についてです。
- イベントリスナをどこに実装させ、どこに更新処理を書くかで迷っている場合、一般的にはイベント処理を行いたいGUI部品に対してイベントリスナを実装し、そのメソッド内で更新処理を行います。
- 例えば、JButton Aがクリックされた場合、JButton Aに対するイベントリスナを実装し、JList Aをこのメソッド内から見えるようにします。そして、JButton Aが押されたときにJButton A用のリストをJList Aに表示するなどの更新処理を行います。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
私の書き込みが中途半端な状態になっているので、勝手に自己完結させて 頂いておきます。 Mediatorパターンを導入するに事よる利点を、(今までのところを)簡潔に まとめておきます。 (1)コンポーネント間の結合が弱くなったので、新しいコンポーネントの追加に あたっても既存の他のコンポーネント(クラス)のコードを見なくてすむ。 (2)コンポーネントが外観上どこに配置されているかの情報に依存しない。 Mediatorがそのコントローラ(の存在)を知ってさえすればよい。 (3)コンポーネントに機能をハードコーディングしていないので、別の機能や 拡張機能を持たせることができる。サンプルのコードで言えば、 コピーボタンは、テキストをコピーするボタンであったが、Mediatorの 実装変更によっては、イメージをコピーするボタンとしても使える。 すなわち、サンプルコードのコピーボタンはかなりの汎用性を持っている かのように見えてきます。しかし、実はまだ大きな欠点があります。 例えば、ここでは、GUIをボタンで実装しましたが、このボタンをMenuItemや ToolButtonに変更したくなったら(または変更するよう命じられたとしたら) どうでしょう。GUI生成部分のコードを変更する必要があるのは当然の ことですが、今の場合にはCopyButtonクラス自体も書き換えなければいけなく なってしまっています。 そこで、この無駄を解消するために、CopyButtonクラスをより抽象化して、 CopyActionクラスとして実装します(MVCパターンによる実装です)。 GUI生成時点に、その生成部のみの変更でViewを自由に設定できるようになります。 これによって、コピーメニューもコピーツールボタンもマウス右クリックに よるコピーサブメニューもCtrl+Cによるコピーアクションも一括管理でき、 このCopyActionクラスは、どんなアプリケーションにも活用できる 非常に汎用的なクラスになることができるのです。 具体的なサンプルコードは省略しますが、これが私が当初書いた AbstractActionクラスを実装するという言葉の意味です。 どうぞ、CopyActuion,PasteActionクラスの実装を行ってみてください。 Javaでプログラムを開発していくとき、多くの場合に必要となる基本的な クラスのひとつでしょうから。
その他の回答 (3)
- HarukaV49
- ベストアンサー率53% (48/89)
残念ながら、完全に本質を見失っておられるように見受けられます。 Mediatorパターンの導入目的は、コンポーネント間の結合を弱めることです。 参照されたWEBサイトの例で言うと、各パネルは別のパネルの存在を 知らないということです。 私の例示したモデルでは、コピーボタンはテキストフィールドの存在を 知らなくてもいいようにコーディングするということです。 すなわち、ボタン、テキストフィールドは(独立した)クラスとして 存在しないとMediatorパターンの導入の価値はないでしょう。 各クラスの機能が単純すぎて、分かり難くなったのかもしれません。 --- CopyButton.java --- import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; public class CopyButton extends JButton implements ActionListener { private Mediator mediator; public CopyButton(Mediator m, String title) { super(title); mediator = m; mediator.register(this); addActionListener(this); } public void actionPerformed(ActionEvent e) { mediator.copy(); } } --- PasteButton.java --- import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; public class PasteButton extends JButton implements ActionListener { private Mediator mediator; public PasteButton(Mediator m, String title) { super(title); mediator = m; mediator.register(this); addActionListener(this); } public void actionPerformed(ActionEvent e) { mediator.paste(); } } --- TextField.java --- import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; public class TextField extends JTextField implements CaretListener { private Mediator mediator; public TextField(Mediator m, String title, int columns) { super(title, columns); mediator = m; mediator.register(this); addCaretListener(this); } public void caretUpdate(CaretEvent e) { if(getSelectedText() == null) { mediator.deselectedText(); } else { mediator.selectedText(); } } } --- Mediator.java --- public class Mediator { private CopyButton copyButton; private PasteButton pasteButton; private TextField textField; public Mediator() { } public void register(CopyButton b) { copyButton = b; b.setEnabled(false); } public void register(PasteButton b) { pasteButton = b; b.setEnabled(false); } public void register(TextField t) { textField = t; } public void selectedText() { copyButton.setEnabled(true); } public void deselectedText() { copyButton.setEnabled(false); } public void copy() { textField.copy(); pasteButton.setEnabled(true); } public void paste() { textField.paste(); } } --- MedSample.java --- import java.awt.Container; import java.awt.FlowLayout; import javax.swing.JFrame; public class MedSample { public static void main(String[] args) { JFrame frame = new JFrame(); Container pane = frame.getContentPane(); pane.setLayout(new FlowLayout()); Mediator mediator = new Mediator(); CopyButton copyButton = new CopyButton(mediator, "Copy"); pane.add(copyButton); PasteButton pasteButton = new PasteButton(mediator, "Paste"); pane.add(pasteButton); TextField textField = new TextField(mediator, "", 15); pane.add(textField); frame.setSize(250, 100); frame.setVisible(true); } } ------ 以上のサンプルコードに対して、Cutボタンを追加してみてください。 その際、CopyButton,PasteButton,TextFieldクラスには全く手を加えず、 Cutボタンの機能を追加できると思います。 これが、Mediatorパターンの実力のひとつです。
- HarukaV49
- ベストアンサー率53% (48/89)
WEBサイトをざっと眺めてみた感じでは、Mediatorパターンに関して サンプルコードが載ったページすら、殆ど見当たらないようですね。 この展開は、私がサンプルコードを提供しないといけなくなってますか?(^^; そうとなればその前に、私が単純なモデルを提案しますので、まずはそれを 実装して見せてください。もちろん、Mediatorパターンを使う必要はありません。 それを元に、Mediatorパターンを使って実装したら、どう分かりやすくなるかを 私が例示させて頂こうと思います。 <実装するサンプルモデル> (1)コンポーネントは、JButton2つとJTextFieldが1つある。 (2)ボタン名は"Copy"と"Paste"とする。 (3)起動時点では、両ボタンともDisableでテキストフィールドは""である。 (4)テキストフィールドに文字が入力され、そのフィールド内の文字を適当に 選択するとCopyボタンがEnableになる。選択解除でDisableに戻る。 (5)Copyボタンが押されると、クリップボードに選択範囲の文字列を コピーし、PasteボタンがEnableに変わる。 (6)Pasteボタンが押されると、テキストフィールドに文字が出力される。 これを、実装してみましょう。 デザインパターンの書籍は、何冊か入手しましょう。 デザインパターンの中では、Mediatorパターンはかなり理解も実装も簡単な パターンだと思っています。ぜひ、まずは自力でMediatorパターンによる実装も 考えてみることをお勧めします。最初は、AbstractActionクラスのことは 忘れてください。ご検討に期待します。
お礼
> デザインパターンの書籍は、何冊か入手しましょう 頑張って出資しようと思います。 過去に結城さんのデザインパターンをペラペラみたことはあるのですが、初心者のわたしにもわかりやすかったのでそちらを買うつもりでいます。 >この展開は、私がサンプルコードを提供しないといけなくなってますか?(^^; いえ、一応サンプルコードは見つけました。 こちらのサイトです。 http://www.pc-view.net/article/70/6.html 上のサイトを斜め読みしながら提案して頂いたモデルを自分なりに実装してみました。 よろしければ添削をお願いします。 と思ったら文字数制限をオーバーしてしまったので、補足欄に書きます。
補足
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; interface Mediator extends ActionListener { } interface Colleague { public void setMediator(Mediator m); } public class PasteCopyTest extends JFrame implements Mediator{ MyPanel panel; String copyString; PasteCopyTest() { panel = new MyPanel(); panel.setMediator(this); this.getContentPane().add(panel); pack(); } public static void main(String[] args) { new PasteCopyTest().setVisible(true); } public void actionPerformed(ActionEvent ae) { String cmd = ae.getActionCommand(); if (cmd.equals("paste-text")) { int pos = panel.textField.getCaretPosition(); String curstr = panel.textField.getText(); panel.textField.setText(curstr.substring(0, pos) + copyString + curstr.substring(pos)); } else if (cmd.equals("copy-text")) { copyString = panel.textField.getSelectedText(); panel.pasteButton.setEnabled(true); } else if (cmd.equals("text-is-selected")) { panel.copyButton.setEnabled(true); } else if (cmd.equals("text-is-unselected")) panel.copyButton.setEnabled(false); } } class MyPanel extends JPanel implements Colleague, ActionListener, CaretListener { private Mediator mediator; final JButton copyButton = new JButton("copy"); final JButton pasteButton = new JButton("paste"); final JTextField textField = new JTextField(); MyPanel () { setLayout(new BorderLayout()); copyButton.setActionCommand("copy-text"); copyButton.addActionListener(this); copyButton.setEnabled(false); add(copyButton, BorderLayout.WEST); pasteButton.setActionCommand("paste-text"); pasteButton.addActionListener(this); pasteButton.setEnabled(false); add(pasteButton, BorderLayout.EAST); textField.addCaretListener(this); add(textField, BorderLayout.NORTH); } public void setMediator(Mediator m) { mediator = m; } public void actionPerformed(ActionEvent ae) { mediator.actionPerformed(ae); } public void caretUpdate(CaretEvent arg0) { if (textField.getSelectedText() != null) mediator.actionPerformed(new ActionEvent(textField, -1, "text-is-selected")); else mediator.actionPerformed(new ActionEvent(textField, -1, "text-is-unselected")); } }
- HarukaV49
- ベストアンサー率53% (48/89)
一般には、Mediatorパターンを使います。 Javaの場合、具体的にはjavax.swing.AbstractActionクラスを 実装することで実現します。 一言で述べれば、各部品同士はお互いの存在を全く知らず、 一人の親分(仲介者;Mediator)が全てを知っていて、 各部品は親分に自分の状態を知らせることで、その親分が、 その状態変化に応じて別の各々の部品に状態を 変化させるよう命令するという方法です。 ご存知でなければ、Mediatorパターンについて、 お調べになってみることをお勧めします。 >例えば、押されるJButton Aにイベントリスナーのメソッドを >実装し、そこで処理を書く場合はJList Aをこのメソッド内から >見えるようにしなけなくて、それをするためにインスタンスを >渡したりするのが面倒に感じています。 このように感じられることが、物凄い才能だと思います!
お礼
ありがとうございます。 >Mediatorパターン というのは知りませんでした。 いくつかのサイトを見てみて、どのようなデザインパターンなのかは多少理解できたのですが今回のケースにどう当てはめればよいかがいまいちピンときません。 javax.swing.AbstractActionを実装するとありますが、これはどういうことか詳しく教えていただけないでしょうか。 >このように感じられることが、物凄い才能だと思います! なんでも面倒だと考えてしまうの性格なので、ある種のプログラミングの才能(根気強さ)が足りないと思っていました(^^;A
補足
お礼欄で質問したことなのですが、 > 体的にはjavax.swing.AbstractActionクラスを > 実装することで実現します というのは、 ・自分でオリジナルのイベントクラスを実装 ・そのイベントを処理するリスナーインターフェースを用意 ・Mediatorにそのインターフェースを実装し、メソッド内で処理を分岐 ということでしょうか?
お礼
お礼と締切りが遅くなってしまい申し訳ありませんでした。 大変勉強になりました。 まだ全ての回答を読んではいないのですが、後日じっくり読ませていただきます。 丁寧に付き合ってくださり、ありがとうございました。