- ベストアンサー
リスナについて
Java を勉強している者です GUIライブラリである awt,swing のリスナについての質問です awt,swing では リスナというイベント処理用のクラスと処理内容を用意して その部品に、イベント用のリスナを登録することによって、コールバックする仕組みになっていると思います。 リスナとイベントの対応ですが、マウスリスナやキーリスナ、ボタンを押したときに対応するアクションリスナ などがありますが、多用する再描画に関しての paintListener がありません 再描画に対応する場合、常に部品を継承して、paintcomponent をオーバーライドして記述しなければなりません 再描画も重要なイベントだと思うのですがなぜリスナが用意されてないのか。 JFrame j = new JFrame(); j.addPaintListener( new PaintAdapter { void onPaint() { ... } } のように描画処理を後付できないかという質問です。 できるようならサンプルのコードを教えてください。 またpaintリスナが用意されない理由があればこれも教えていただけると幸いです。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
JFrameのペイントイベントは利用価値が低いので、 JPanel用の再描画イベント作成してみました。 JFrameの再描画イベントも同様な方法で作成可能ですが、 JFrameには、まずJPanelを設定して使うのが普通だと思いますので このイベントで困ることはまずないのではないかと想像します。 --------- PaintEventablePanel.java --------- import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.LayoutManager; import javax.swing.JPanel; /** * パネルが再描画されたとき、PaintEvent を生成します。 */ public class PaintEventablePanel extends JPanel { /** * ダブルバッファーおよびフローレイアウトで新しい JPanel を作成します。 */ public PaintEventablePanel() { } /** * FlowLayout および指定されたバッファリング方式で新しい JPanel を作成します。 * isDoubleBuffered が true の場合、JPanel はダブルバッファーを使用します。 * @param isDoubleBuffered true の場合はダブルバッファリング方式で、 * 追加メモリー空間を利用することにより、高速でちらつきのない 変更を行う */ public PaintEventablePanel( boolean isDoubleBuffered ) { super( isDoubleBuffered ); } /** * 指定されたレイアウトマネージャーで、新しい JPanel を作成します。 * @param layoutManager 使用する LayoutManager */ public PaintEventablePanel( LayoutManager layoutManager ) { super( layoutManager ); } /** * 指定されたレイアウトマネージャーおよびバッファリング方式で新しい JPanel を作成します。 * @param layoutManager 使用する LayoutManager * @param isDoubleBuffered true の場合はダブルバッファリング方式で、 * 追加メモリー空間を利用することにより、高速でちらつきのない 変更を行う */ public PaintEventablePanel( LayoutManager layoutManager, boolean isDoubleBuffered ) { super( layoutManager, isDoubleBuffered ); } /** * このメソッドをサブクラスでオーバーライドする場合は、 * 渡された Graphics のオブジェクトには永続的な変更は行わないようにします。 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ public void paintComponent( Graphics g ) { super.paintComponent(g); PaintListener[] listeners = getRepaintListeners(); for(int i=0, n=listeners.length; i<n; i++) { listeners[i].painted( new PaintEvent(this, (Graphics2D)g) ); } } /** * listener を登録し、パネルが再描画されるときにそのリスナが * RepaintEvent を受け取れるようにします。 * @param listener 登録するリスナ */ public void addPaintListener( PaintListener listener ) { listenerList.add( PaintListener.class, listener ); } /** * 登録済みのリスナを削除します。 * @param listener 削除するリスナ */ public void removeRepaintListener( PaintListener listener ) { listenerList.remove( PaintListener.class, listener ); } /** * 登録されている再描画リスナの個数を返します。 * @return リスナの個数 */ public int getRepaintListenerCount() { return listenerList.getListenerCount( PaintListener.class ); } /** * 全ての再描画リスナのリストを返します。 * @return リスナ配列 */ public PaintListener[] getRepaintListeners() { return listenerList.getListeners( PaintListener.class ); } } --------- PaintListener.java --------- import java.util.EventListener; /** * パネルが再描画されたことを受け取るためのリスナインターフェースです。 */ public interface PaintListener extends EventListener { /** * 再描画されると呼び出されます。 * @param e リペイントイベント */ void painted( PaintEvent e ); } --------- PaintEvent.java --------- import java.awt.Graphics2D; import java.util.EventObject; /** * パネルが再描画されたときに呼び出されるイベントです。 */ public class PaintEvent extends EventObject { private Graphics2D g; /** * イベントを生成します。 * @param source イベントの発生したパネル * @param g パネルのグラフィックス */ public PaintEvent( Object source, Graphics2D g ) { super( source ); this.g = g; } /** * 再描画されたグラフィックスを返します。 * @return Graphics2Dオブジェクト */ public Graphics2D getGraphics() { return g; } }
その他の回答 (1)
- _ranco_
- ベストアンサー率58% (126/214)
Java的な概念ないしMVC的な概念では、ペイントはそれ自身がコントローラロジックを発動するわけではないので、イベントとは呼べません。ペイント、正確にはリペイント(再描画)は、システムが行うものに対してはComponentListenerで対応し、プログラマの意思で行うものについては単純にrepaint()リクエストでその意思表示をするだけです。 イベント/リスナという枠組みで処理されるものは、わりと高いレベルのロジックを持つタスクです。少なくとも従来の標準的なMVCの実装では。
お礼
早速のお返事有り難うございます。 ちょっと内容を読みとれていないかもしれませんが awt,swing は MVC に則して設計されていて MVC の元では、描画系の機能は View 側の責務なのでコントローラーの範疇であるイベントとして扱うには不適当ということでしょうか。 だからswing ではそういう設計にはなっていないと。 swing のMVCについて理解する必要がありそうです。 http://java.sun.com/products/jfc/tsc/articles/architecture/index.html このページを見つけたので解読中です。 ご紹介のURLのページはとても参考になりそうです。有り難うございます。 きちんと身につければ理解が深まると思います。
お礼
ご返答有り難うございます。 サンプルコードとても参考になります。独自のペイントイベントやリスナを作り、paintComponent()のときに呼び出すという仕組みのようですね。 このコードを参考にして次のステップとしてJPanel 以外の部品でも簡単に利用可能になるようなものを研究中です。 /* 再描画可能な性質を表す */ interface PaintEvantable { addPaintListener(PaintListener listener); } ArrayList<PaintEventable> 再描画部品リスト = new ArrayList<PaintEventable>(); PaintEventable 部品1 = create_PaintEvent_Component(new JPanel()); PaintEventable 部品2 = create_PaintEvent_Component(new JButton()); PaintEventable 部品3 = create_PaintEvent_Component(new JButton()); 再描画部品リスト.add(部品1,部品2,部品3); class MyPaintListener implement PaintListener { void painted( PaintEvent e ) { e.getGraphics().draw(...)l } } PaintListener 描画機能A = new MyPaintListener(); /* /* すべての部品に横断的に同じ描画機能を組み込む /* foreach (PaintEventable temp in 再描画部品リスト) { temp.addPaintListener(描画機能A); }