• ベストアンサー

リスナについて

Java を勉強している者です GUIライブラリである awt,swing のリスナについての質問です awt,swing では リスナというイベント処理用のクラスと処理内容を用意して その部品に、イベント用のリスナを登録することによって、コールバックする仕組みになっていると思います。 リスナとイベントの対応ですが、マウスリスナやキーリスナ、ボタンを押したときに対応するアクションリスナ などがありますが、多用する再描画に関しての paintListener がありません 再描画に対応する場合、常に部品を継承して、paintcomponent をオーバーライドして記述しなければなりません 再描画も重要なイベントだと思うのですがなぜリスナが用意されてないのか。 JFrame j = new JFrame(); j.addPaintListener( new PaintAdapter { void onPaint() { ... } } のように描画処理を後付できないかという質問です。 できるようならサンプルのコードを教えてください。 またpaintリスナが用意されない理由があればこれも教えていただけると幸いです。

  • Java
  • 回答数2
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.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; } }

pica_zip
質問者

お礼

ご返答有り難うございます。 サンプルコードとても参考になります。独自のペイントイベントやリスナを作り、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); }

その他の回答 (1)

  • _ranco_
  • ベストアンサー率58% (126/214)
回答No.1

Java的な概念ないしMVC的な概念では、ペイントはそれ自身がコントローラロジックを発動するわけではないので、イベントとは呼べません。ペイント、正確にはリペイント(再描画)は、システムが行うものに対してはComponentListenerで対応し、プログラマの意思で行うものについては単純にrepaint()リクエストでその意思表示をするだけです。 イベント/リスナという枠組みで処理されるものは、わりと高いレベルのロジックを持つタスクです。少なくとも従来の標準的なMVCの実装では。

参考URL:
http://homepage1.nifty.com/algafield/paint.html
pica_zip
質問者

お礼

早速のお返事有り難うございます。 ちょっと内容を読みとれていないかもしれませんが awt,swing は MVC に則して設計されていて MVC の元では、描画系の機能は View 側の責務なのでコントローラーの範疇であるイベントとして扱うには不適当ということでしょうか。 だからswing ではそういう設計にはなっていないと。 swing のMVCについて理解する必要がありそうです。 http://java.sun.com/products/jfc/tsc/articles/architecture/index.html このページを見つけたので解読中です。 ご紹介のURLのページはとても参考になりそうです。有り難うございます。 きちんと身につければ理解が深まると思います。

関連するQ&A

  • SwingのpaintComponent()メソッドについて

     JAVA初心者です、宜しくお願いします。  参考書で、Swingについて以下のようなコメントを見つけました、ただ何故そうなのかの理由を書いていません。  以下の内容はどのような理由からそうなるのでしょうか。  「Swing コンポーネントでは、メソッドpaintは推奨されていません。  paintComponentをプログラムから呼び出してはいけません。描画をしたい場合は、 paintComponent をオーバー ライドしたクラスの repaint() メソッドを呼び出します。  Swing コンポーネント上に描画するには、 描画したいコンポーネントのクラスを継承したクラスで、 メソッド paintComponent(Graphics g) をオーバーライドし、 パラメータで渡された g に対して Graphics クラスのメソッドで描画をします。  オーバーライドした paintComponent の先頭で、このコンポーネントの土台を描画するために、 super.paintComponent(g) を呼び出しておきます。」  宜しくお願いします。

    • ベストアンサー
    • Java
  • 簡単なこーどですが、エラーの原因が分かりません

    今晩は、JAVAの初心者です、宜しくお願いします。 下のコードでエラーがでます、いくら考えても原因がさっぱり分かりません。 一体何処が悪いのでしょうか、宜しくお願いします。 また、最後の「j.show();」では警告が出ています。 何が原因でしょう?? ============================================================ import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; class JFrame_Ohayou extends JFrame implements WindowListener{ /*********** コンストラクタ ********************/ public JFrame_Ohayou(){ setSize(400,300); setTitle("JFrameのテスト"); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } /******************* paint ***********************/ public void paint(Graphics g){ super.paint(g); g.drawString("おはよう",20,40); } } /******************* main ***********************/ public class JFrameTest{ public static void main(String[] args){ JFrame_Ohayou j = new JFrame_Ohayou(); j.show(); } } =============================================================

    • ベストアンサー
    • Java
  • Swingについての質問です

    Swingについての質問です  まだJava初心者です^^。とんでもない質問でしたらすいません。  Swingの中の、JFrameを使って、ある図形を描画するという場面です。描画はできたのですが、コンピュータの画面から図形がはみ出してしまって、全体を見る事ができません。そこで、スクロールバーを表示したいと思っているのですが、その方法はどうすれば良いのでしょうか?  下に、普段私が使っている、一本の線を描画するサンプルを書いておきます。 import java.awt.*; import javax.swing.*; public class Sample extend JPanel { public static void main(String[] args){ JFrame frame = new JFrame("Sample"); TestFrame tf = new TestFrame(); frame.add(tf); frame.getComponents().add(tf); frame.setSize(120, 120); //ウインドウサイズを120×120に指定 frame.setBackground(Color.WHITE); frame.setVisible(true); } } class TestFrame extends JPanel{ void paintComponent(Graphics g){ g.drawLine(10, 10, 100, 100); //(10, 10)から(100, 100)に線を描画 } }  もちろんこの場合はスクロールバーは必要ないですが、このような場合でもウインドウサイズを50×50のような小さいサイズにしてしまったときだけスクロールバーが現れるようにできたらもっと嬉しいです。  回答宜しくお願いします。

    • ベストアンサー
    • Java
  • TABキーの検出

    Swingコンポーネントで、TABキーのイベントを取得する 方法を教えてください。 タブキー以外は検出できるのですが… import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JFrame; import javax.swing.JPanel; public class TabKeyListener { public TabKeyListener() { JPanel panel = new JPanel(); panel.addKeyListener( new KeyListener(){ public void keyPressed(KeyEvent e) { System.out.println(e.getKeyCode()); } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } } ); JFrame frame = new JFrame(); frame.add(panel); frame.setBounds(100,100,200,200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); panel.requestFocusInWindow(); } public static void main(String[] args) { new TabKeyListener(); } }

    • ベストアンサー
    • Java
  • イベント処理がうまくいきません。

    java初心者です。 スタートボタンをクリックするとトランプ52枚表示されるようにしたいのですが、 1枚も表示されず、原因もよく分からないため苦労してます。 よろしくお願い致します。 以下は、プログラムです。 import java.awt.Color; import java.awt.Dimension; import java.awt.*; import javax.swing.*; import java.io.*; import javax.imageio.*; import java.awt.Graphics; import java.awt.Font; import javax.swing.JButton; import java.awt.Container; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.event.*; public class narabi2 extends JPanel{ JButton btn1,btn2,btn3; static Image img[] = new Image[52]; public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(f.EXIT_ON_CLOSE); f.setResizable(true); f.setVisible(true); new narabi2(); } public narabi2(){ btn1 = new JButton("スタート"); this.add(btn1); btn1.addActionListener(new ev()); btn2 = new JButton("ランキング"); this.add(btn2); btn2.addActionListener(new ev()); btn3 = new JButton("ログアウト"); this.add(btn3); btn3.addActionListener(new ev()); JFrame f = new JFrame(); f.setSize(900,840); f.getContentPane().setBackground(new Color(0,100,0)); f.setDefaultCloseOperation(f.EXIT_ON_CLOSE); f.setResizable(true); f.setVisible(true); f.add(this); } public void paintComponent(Graphics g){ super.paintComponent(g); btn1 = new JButton("スタート"); this.add(btn1); btn1.addActionListener(new ev()); btn2 = new JButton("ランキング"); this.add(btn2); btn2.addActionListener(new ev()); btn3 = new JButton("ログアウト"); this.add(btn3); btn3.addActionListener(new ev()); setBackground(new Color(0,100,0)); int i;               //カードを並べる処理 int x = 0,y=0; for (i = 0; i < 52; i++) { g.drawImage(img[i], x, y, null); x = x + 100; if(x>=900){ x=0; y=y+140; } } } class ev implements ActionListener{ public void actionPerformed(ActionEvent m){ if(m.getSource()==btn1) //スタート { //public static void main(String[] args) { // 画像ファイルの読み込み int i, j; int no = 0; String c[] = {"s","h","c","d"}; try { for(i = 0; i < 4; i++) { for(j = 1; j <= 13; j++) { //String filename = "cards.png"; String filename = String.format("cards/%s%02d.png", c[i], j); img[no] = ImageIO.read(new File(filename)); no++; } } } catch(Exception e) { System.out.println(e); System.exit(0); } // シャッフル Image w; for (i = 51; i >= 0; i--) { j = (int)(Math.random() * (i + 1)); w = img[i]; img[i] = img[j]; img[j] = w; } } /*public void paintComponent(Graphics g) { super.paintComponent(g); int i; int x = 0,y=0; for (i = 0; i < 52; i++) { g.drawImage(img[i], x, y, null); x = x + 100; if(x>=900){ x=0; y=y+140; } } }*/ } /*else if(m.getSource()==btn2) //ランキング { } else if(m.getSource()==btn3) //ログアウト { } }*/ } }

  • createImage()を使いコンパイル

    このプログラムをcreateImage()を使ってイメージを作りたいのですが自分で変更してもコンパイルできません><;どのように変更したらイメージをつくることができるのでしょうか?回答よろしくおねがいしまあす(^^; import java.awt.Color; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.JComponent; import javax.swing.JFrame; class Test extends JComponent implements MouseMotionListener { public static void main(String[] args) { JFrame frame = new JFrame(); frame.getContentPane().add(new Test()); frame.setBounds(0 , 0 , 400 , 300); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT ON CLOSE); } Image image; public Test() { addMouseMotionListener(this); image = new BufferedImage(400, 300, BufferedImage.TYPE INT RGB); Graphics g = image.getGraphics(); g.setColor(new Color(0xFF, 0xFF, 0xFF)); g.fillRect(0, 0, 400, 300); }public void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); } public void mouseDragged(MouseEvent e) { Graphics g = image.getGraphics(); g.setColor(new Color(0, 0, 0)); g.fillOval(e.getX() - 5, e.getY() - 5, 5 , 5); repaint(); }public void mouseMoved(MouseEvent e) {} }

  • createImage()を使い コンパイル

    このプログラムをcreateImage()を使ってイメージを作りたいのですが自分で変更してもコンパイルできません><;どのように変更したらイメージをつくることができるのでしょうか?回答よろしくおねがいしまあす(^^; import java.awt.Color; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.JComponent; import javax.swing.JFrame; class Test extends JComponent implements MouseMotionListener { public static void main(String[] args) { JFrame frame = new JFrame(); frame.getContentPane().add(new Test()); frame.setBounds(0 , 0 , 400 , 300); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT ON CLOSE); } Image image; public Test() { addMouseMotionListener(this); image = new BufferedImage(400, 300, BufferedImage.TYPE INT RGB); Graphics g = image.getGraphics(); g.setColor(new Color(0xFF, 0xFF, 0xFF)); g.fillRect(0, 0, 400, 300); }public void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); } public void mouseDragged(MouseEvent e) { Graphics g = image.getGraphics(); g.setColor(new Color(0, 0, 0)); g.fillOval(e.getX() - 5, e.getY() - 5, 5 , 5); repaint(); }public void mouseMoved(MouseEvent e) {} }

  • イベントとリスナーに関すること

     Javaの初心者です。AWTについてご質問します。 処理をしたい手順として (1) したい処理の手順の選択(Aの処理か、Bの処理か、のように)をRadio Button で選択し (2) データの入力(Aの処理に対するデータ、Bの処理に対するデータ、の入力)を行い (3) それぞれの処理の実行と結果の表示、これをButton で促す。 の手順でプログラムを行いたいのです。((1)と(2)を逆にすれば実行できることは確認しましたが、何とか自然な形でということで上記の手順で行いたいのです。)  私の作ったプログラムではリスナーの中から内部クラスで定義された別のリスナーを呼び出すという形になってしまいます。これではだめらしいのです。呼び出し側で、その内部クラスの生成を行った後、実行のためのメソッドにはenableを使ってしまいました。どのメソッドを添えたらよいのかわからなくて苦し紛れに使いました。 内部クラスの初期設定の部分までは実行されているのですが、イベントハンドラであるactionPerformedの中で書かれた命令は実行されていません。 AWTに堪能な方、お時間を煩わせて申し訳ありませんが、お教えくださいますようお願い申し上げます。

    • ベストアンサー
    • Java
  • javaでgraphicsの描画の件

    今日は javaでgraphicsの描画を行っていますが、CENTERのペインには、描画できますが、 それ以外のペイン(NORTH,WEST、EAST,、SOUTH)には、描画できないように思います。 Q1)この件について、コメント頂けますと大変助かります。 下記に、ソースコードを添付いたします。 =================== package pkg; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.Line2D; import javax.swing.JFrame; import javax.swing.JPanel; public class SampleApp extends JFrame { public SampleApp(){ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(600, 300); this.add(new GPanel(), BorderLayout.WEST); this.add(new GPanel(), BorderLayout.CENTER); } public static void main(String[] args) { new SampleApp().setVisible(true); } } class GPanel extends JPanel { @Override public void paintComponent(Graphics g) { super.paintComponent(g); // int w = this.getWidth(); // int h = this.getHeight(); int w=200; int h=200; g.setColor(Color.RED); g.fillOval(0, 0, w/2, h/2); Graphics2D g2 = (Graphics2D)g; g2.draw(new Line2D.Double(40, 40, w,h)); g.setColor(Color.BLUE); g.setFont(new Font("Serif", Font.BOLD, 36)); g.drawString("Graphics draw!", 10, h - 50); // g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.draw(new Line2D.Double(30.0d, 50.0d, 180.0d, 140.0d)); g2.setPaint(Color.PINK); BasicStroke wideStroke = new BasicStroke(8.0f); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(30.0d, 120.0d, 250.0d, 70.0d)); } }

    • ベストアンサー
    • Java
  • java(swing)で、登録ボタンを押すとファイルを読み込みDBに登

    java(swing)で、登録ボタンを押すとファイルを読み込みDBに登録する処理です。 その処理で、登録ボタンを押すと、ダイアログを起動して、処理中とメッセージ表示したいのですが、データが多く、画面が固まった状態になり、メッセージが表示されないのです。何かいい方法ありますでしょうか? ******************************************************************* import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class topMain { public static void main(String[] args) { //メニュー画面を起動する topMain frame = new topMain(); frame.topFrame(); } private void topFrame() { JFrame jf = new JFrame(); //フレームのサイズ設定 jf.setSize(1000, 600); jf.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); jf.getContentPane().setLayout(null); JButton b1 = new JButton("登録ボタン"); b1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //ダイアログボックスを開く     //ダイアログボックスは起動するが、 //メッセージが表示されない、 //おそらく大きいデータを読むとき画面が固まるため //重いファイルを読み込む //DB登録処理 //ダイアログを閉じる } }); jf.getContentPane().add(b1); b1.setBounds(40, 400, 240, 100); jf.setVisible(true); } } *******************************************************************

専門家に質問してみよう