JFrameクラスの挙動に関する質問と推察

このQ&Aのポイント
  • JFrameクラスを使用してWindowを表示するためのアプリを作成中ですが、repaintがうまく動作しません。
  • Main文でrepaintを実行しても画面が更新されない原因として、JFrameが自動で作成したインスタンスとdrowインスタンスの間に関係がないことが考えられます。
  • この問題を解決するためには、repaintを実行する際にJFrameのインスタンスと関連付ける必要があります。
回答を見る
  • ベストアンサー

JFrameクラスの挙動に対する推察と質問

JFrameクラスの挙動に対する推察と質問 現在、プログラムでJFrameクラスを使って,Windowを表示させるアプリをつくっているのですが、repaintがうまく動作しません。 コードで説明させていただきますと、 public class Main{   public static void main(String[] args){     Drow drow ;     drow = new Drow();     drow.createFrame();     drow.repaint();//画面は更新されない   } } public class Drow extends JPanel{   JFrame frame;   static Image jpg;   static int x;   static int y;   public void createFrame()    {     frame = new JFrame();     Drow app = new Drow();     frame.getContentPane().add(app);     frame.getContentPane().add( new Drow() );     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     frame.setBounds(10, 10, 300, 200);     frame.setTitle("タイトル");     frame.setVisible(true);   }   public void paintComponent(Graphics g){     super.paintComponent(g);     g.drawOval(x, y, 80, 80);   } } このソースのMain文でrepaintを実行させているのですが、画面は更新されません。 このエラーについて自分なりに原因を推察した所、JFrameは自分で自分のクラスのインスタンスを作成しているからではないかと考えました。 なので私がrepaintを実行しても、それは私の作ったdrowインスタンスのpaintComponentが実行されているだけで、JFrameが自動でつくったインスタンスの方には影響がないのだと推察しました。 ここで質問なのですが、私の推察はあっているでしょうか? また、このようなrepaintをMain文で実行したい場合はどのようにしたらよいのでしょうか? お返事お待ちしております。

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

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

  • ベストアンサー
  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.4

 またまた#1です。 >これはswingが別のスレッドで動いているから、別の >スレッドからアクセスしてはいけないということですか? >それともMainからSwingが一連のスレッドなので、 >そもそも横からアクセスできないということですか?  これの正解は、 >これはswingが別のスレッドで動いているから、別の >スレッドからアクセスしてはいけないということですか?  こっちですね。  サンプルコードのMainFrameクラスのmainメソッド、およびDrowクラスのstartメソッドを見てみてください。 System.out.println("main = " + Thread.currentThread().getName()); System.out.println("GUI = " + Thread.currentThread().getName());  それぞれ、現在のスレッド名を表示するコードです。  実行してみるとわかると思いますが、結果は下記の通りです。 main = main GUI = AWT-EventQueue-0  Javaアプリケーションが実行されるとまず、mainと言う名前のスレッドが作られ、そのmainスレッドがmainメソッドを実行します。 (今回は、すぐにmainメソッドを抜けて終了してしまいます)  しかし、JFrameなどのイベントで走っているスレッドは、これとは違います。  JFrameが表示されるときに、イベントディスパッチスレッドと呼ばれる専用のスレッドが作られ、GUIの描画とイベントの処理などは、このスレッドに任されます。  Swingは、複数のスレッドに同時実行されることを考慮されて作られていないシングルスレッド設計なので、このイベントディスパッチスレッド以外のスレッドが直接Swingコンポーネントにアクセスすると問題が発生する可能性があるのです。

lain_003
質問者

お礼

返事が遅くなってすいません。 わかりやすいサンプルコードを書いていただきありがとうございます。 JFrameなどのイベントで走っているスレッドはmainとは違うのですね。 おかげさまで解決することができました。長い間お付き合いいただきありがとうございました。

その他の回答 (3)

  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.3

 再び#1です。  メインとなるJFrameのクラスです。  アニメの機能をDrowにまとめたので、こちらは、すっきりわかりやすくすることができます。  また、DrowクラスはMainFrameクラスに依存していないので、ほかのクラスでも使い回すことができます。 (コンパイルするときは全角スペースを半角スペースに置換してからにしてください) public class MainFrame extends JFrame {   private Drow drow;   private JButton startButton;   private JButton stopButton;   public MainFrame() {     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     drow = new Drow();     getContentPane().add(drow, BorderLayout.CENTER);     JPanel panel = new JPanel();     startButton = new JButton("Start");     startButton.addActionListener(new StartButtonClicked());     panel.add(startButton);     stopButton = new JButton("Stop");     stopButton.addActionListener(new StopButtonClicked());     panel.add(stopButton);     getContentPane().add(panel, BorderLayout.SOUTH);     pack();   }   private class StartButtonClicked implements ActionListener {     public void actionPerformed(ActionEvent e) {       drow.start();     }   }   private class StopButtonClicked implements ActionListener {     public void actionPerformed(ActionEvent e) {       drow.stop();     }   }   public static void main(String[] args) {     System.out.println("main = " + Thread.currentThread().getName());     SwingUtilities.invokeLater(new Runnable() {       public void run() {         MainFrame frame = new MainFrame();         frame.setVisible(true);       }     });   } }

  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.2

 こんばんは、#1です。  クラスの設計についてですが、クラスの親子関係が逆転しているように見えます。  まず、粒度の細かいクラスを作っていき、その親となるべきクラスが、そのインスタンスを保持するという形にしていくのが基本だと思います。  今回で言えば、丸を表示するクラスであるDrowは、部品となるべき言わば粒度の細かいクラスであり、できるだけ他のクラスに依存しないように、機能をまとめて実装します。  そして、親となるべきJFrameのクラスで、インスタンス化して、それを保持するという形がいいと思います。  実際どのようなものを作ろうとしておられるのかよくわからなかったので、丸が移動するサンプルを作ってみました。  まずは、Drowクラスです。 (コンパイルするときは全角スペースを半角スペースに置換してからにしてください) public class Drow extends JPanel {   private int x;   private int y;   private Timer timer;   public Drow() {     timer = new Timer(33, new TimerAction());     x = 100;     y = 150;     setPreferredSize(new Dimension(600, 400));   }   //アニメをスタートさせるメソッド   public void start() {     System.out.println("GUI = " + Thread.currentThread().getName());     x = 100;     timer.start();   }   //アニメをストップするメソッド   public void stop() {     timer.stop();   }   @Override   protected void paintComponent(Graphics g) {     super.paintComponent(g);     g.drawOval(x, y, 80, 80);   }   private class TimerAction implements ActionListener {     public void actionPerformed(ActionEvent e) {       if (x > 400) {         timer.stop();       } else {         x += 4;         repaint();       }     }   } }

  • PecoPlus
  • ベストアンサー率76% (144/188)
回答No.1

 こんばんは。  推察に関しては、その通りだと思います。  つまり、クラスの設計そのものが、ちょっと変ですね。 >また、このようなrepaintをMain文で実行したい >場合はどのようにしたらよいのでしょうか?  mainメソッドで、repaintしようと言うことがそもそも間違っています。  mainメソッド内で、そのまま、repaint メソッドを呼ぶと言うことは、メインスレッドから swing コンポーネントにアクセスすると言うことで、シングルスレッド設計の swing に対してはしてはいけないことです。  円を動かすアニメーションか何かをしたいのだとしたら、javax.swing.Timer を GUI を構築するクラスに組み込んで使うべきだと思いますし、どうしても、メインメソッドからアクセスしたいのでしたら、SwingUtilities.invokeLater() を使うべきです。

lain_003
質問者

補足

自分の理解力不足のため、いろいろと疑問点がでてきたのでさらに質問させていただきます。 <<つまり、クラスの設計そのものが、ちょっと変ですね。 これは自分のソースがへんってことですよね?どのようにするのが一般的なんですか? <<シングルスレッド設計の swing に対してはしてはいけないことです。 これはswingが別のスレッドで動いているから、別のスレッドからアクセスしてはいけないということですか?それともMainからSwingが一連のスレッドなので、そもそも横からアクセスできないということですか? <<javax.swing.Timer を GUI を構 これはこのAPIでrepaintを呼び出すということでいいんですよね? 質問攻めとなってしまいましたが、よろしければお返事をいただけるとうれしいです。

関連するQ&A

  • swingのJframeについて

    JFrameについて質問があるのですが import javax.swing.*; public class JFrameTest extends JFrame{ public static void main(String[] args){ JFrameTest frame = new JFrameTest(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } JFrameTest(){ JPanel p = new JPanel();   Container contentPane = getContentPane(); ContentPane.add(p);   pack(); } } このプログラムと import javax.swing.*; public class JFrameTest{ public static void main(String[] args){ JFrame frame = new JFrame("フレームのタイトル"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds( 10, 10, 300, 200); frame.setVisible(true); JPanel p = new JPanel();   Container contentPane = frame.getContentPane(); frame.ContentPane.add(p);   frame.pack(); } } このプログラムは何が違うのでしょう? やってることはまったく一緒だと思ってたのですが、全然違うみたいです。 上のプログラムの JFrameTest(){ はコンストラクタと呼ばれるものなのでしょうか? しょぼい質問で申し訳ないのですが誰か教えていただけないでしょうか。

    • ベストアンサー
    • Java
  • Jframeの中にJframeを表示させたい

    Jframeの中にボタンを作り、ボタンを押すとJInternalFrameではなくJframeを表示させるようにしたいんですが、なかなかできません。 検索したりしてサンプル探したんですが、 Jframeを表示させ、ラベルを貼ったりしたいんですが どなたかお願いします!! public class Browser extends JFrame{ public static void main(String args[]) { Browser frame = new Browser(); frame.setTitle(""); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setVisible(true); } //ボタン private JButton bt = new JButton("~~"); public Browser() { bt.addActionListener(this); JToolBar tb = new JToolBar(); tb.setFloatable(false); getContentPane().add(tb, BorderLayout.NORTH); JPanel panel2 = new JPanel(); panel2.add(bt); panel2.setLayout(new FlowLayout(FlowLayout.LEFT)); tb.add(panel2); } //↓この辺りの処理の記述で頭が混乱してきました(泣 public class actionPerformed(ActionEvent e){ if(e.getSource() == bt){ Frame FW = new Frame(); FW.setSize(500,400); FW.setVisible(true); } } class Frame extends Frame{ public Frame(){ //コンストラクタの定義 } }

    • ベストアンサー
    • Java
  • 内部クラスにする方法教えてください!

    import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Line extends JPanel { int x0, y0, x1, y1; public static class WindowCloser extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public static class ClickTracker extends MouseAdapter { private Line line; public ClickTracker(Line enclosing) { line = enclosing; } public void mouseClicked(MouseEvent e) { line.x0 = line.x1; line.y0 = line.y1; line.x1 = e.getX(); // MouseEventクラスのgetXメソッドでマウスのx座標値を取得 line.y1 = e.getY(); // MouseEventクラスのgetYメソッドでマウスのx座標値を取得 line.repaint(); // ウィンドウの表示を再描画 } } public Line() { x0 = y0 = x1 = y1 = 0; addMouseListener(new ClickTracker(this)); JFrame frame = new JFrame(); frame.addWindowListener(new WindowCloser()); frame.getContentPane().add(this); frame.setSize(300,300); frame.setVisible(true); } public void paintComponent(Graphics g) { super.paintComponent(g); g.drawLine(x0, y0, x1, y1); } public static void main(String[] args) { Line c = new Line(); } } 上のプログラムのClickTrackerクラスを内部クラスに書き換えたいんですけどどなたか教えてください!

    • ベストアンサー
    • Java
  • Swing自作コンポーネントをadd出来るように、

    JTextFieldやJButtonなどを一つにまとめたコンポーネントを自作し、それをadd()出来るようにしたいです。frame.add(自作のクラスのインスタンス)を可能にしたいです。 調べて、paintComponent()を使えば良いということはわかったのですが、Graphicsのインスタンス(?)に線を描いたり、円を描いたりする方法はわかりましたが、JButtonやJTextFieldなどをGraphicsのインスタンス(?)に追加する方法はわからず、paintComponent()を使うやり方はできませんでした。 paintComponent()も使わずに、自分のできる方法で、組んだものを一応載せます。 import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; public class MyComponentTest{ public static void main(String[] args){ JFrame frame = new JFrame("タイトル"); frame.setSize(400, 300); frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)); // 2つのテキストフィールドと一つのボタンを4つ追加する frame.add(new TwoTextFieldsAndOneButton().getContent()); frame.add(new TwoTextFieldsAndOneButton().getContent()); frame.add(new TwoTextFieldsAndOneButton().getContent()); frame.add(new TwoTextFieldsAndOneButton().getContent()); frame.setVisible(true); } } //2つのテキストフィールドと一つのボタンを一つの部品にしたい class TwoTextFieldsAndOneButton{ JTextField textField1 = new JTextField("テキストフィールド1"); JTextField textField2 = new JTextField("テキストフィールド2"); JButton button = new JButton("ボタン"); // こんなメソッドを使わずに、再現したい JPanel getContent(){ JPanel panel = new JPanel(); panel.add(textField1); panel.add(textField2); panel.add(button); return panel; } }

    • ベストアンサー
    • Java
  • SwingでgetContentPaneのエラーです、お願いします

     今晩は、java勉強中のものです、宜しくお願いします。  下のようなプログラムを組んでみましたが、「型JFrameから非staticメソッドgetContentPane()にstatic参照 することは出来ません」というエラーコードです。  原因が良く分かりません、どなたか教えて下さい。  いくら考えても原因がよく分かりません、宜しくお願いします。 ================================================================ public class Panel_train extends JFrame{ public static void main(String[] args) { Container cnt = getContentPane(); JPanel jpanel = new JPanel(); JTextArea jtext = new JTextArea("Hello World", 100, 50); jpanel.add(jtext); cnt.add(jpanel, BorderLayout.CENTER); JFrame frame = new JFrame("テスト"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 100); frame.setVisible(true); } }

    • ベストアンサー
    • Java
  •  static 参照するには??

     static 参照するには??  Java初心者です、宜しくお願いします。  下のようなプログラムを書きましたが、「Container gc = getContentPane();」 の箇所で、「型 JFrame の非 static メソッド getContentPane() を static 参照することはできません」とエラーが出ます。 意味がわかりません、またどのように変更してやればよいのでしょうか。 宜しくお願いします。  ======================================================================= class Canvas1 extends JFrame { public void paint(Graphics g) { g.drawRect(150, 150, 50, 50); } } public class SimpleDraw extends JFrame { public static void main(String[] args) { JFrame jf = new JFrame(); JPanel jp = new JPanel(); Container gc = getContentPane(); gc.add(jp); Canvas1 c = new Canvas1; jp.add(c); jf.add(jp); jf.setVisible(true); } }

    • ベストアンサー
    • Java
  • javaのswingについて

    swingを使う場合、絶対mainの中で udp u=new udp(); JFrame frame = new JFrame("チャットプログラム"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ウィンドウを閉じたときにアプリケーションを終了する frame.setJMenuBar(u.menuBar); frame.getContentPane().add(u.sp, "North"); frame.getContentPane().add(u.buttonPanel, "Center"); frame.getContentPane().add(u.tfPanel, "South"); frame.pack(); // ウィンドウを適切な大きさにする frame.setVisible(true); // ウィンドウを可視化する などをしないといけないのでしょうか? mainのクラスからgamenといったクラスをnewするかたちにする方法はありますか? 何か良い方法はないでしょうか?

  • 「削除するか、クラスパスの正しいサブディレクトリにあるかを確認してください」とコンパイルエラーになってしまいます!

    下記のソースコードをコンパイルすると 「HelloWorldSwing.java:6: JFrame にアクセスできません。 クラスファイル .\JFrame.java は不正です。 ファイルにクラス JFrame が含まれていません。 削除するか、クラスパスの正しいサブディレクトリにあるかを確認してください。 JFrame frame = new JFrame("HelloWorldSwing");」 と表示されてしまいエラーになってしまいます。 どなたか、分かる方がいましたらアドバイスください!! <HelloWorldSwing.java>--------------------------- import javax.swing.*; public class HelloWorldSwing { public static void main(String[] args) { JFrame frame = new JFrame("HelloWorldSwing"); final JLabel label = new JLabel("Hello World"); frame.getContentPane().add(label); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } } -------------------------------------------------

    • ベストアンサー
    • Java
  • Java JFrameにJPanelを・・・

    こんにちは。趣味でプログラミングをしているものです。 さっそくですが、質問させていただきます。 Java で電卓を作っているのですが、 文具店で1000円くらいで販売している電卓を再現したいのですが、 いろいろなボタンの操作はなんとなくわかってきたのですが、 電卓のGUIについて質問させていただきます。 JFrame を継承したクラスに背景の画像を描画し その上に、計算の経過、結果を表示するJPanelを 継承したクラスのインスタンスを 特定の座標に配置したいのですが、 うまくいきません。 以下に自分の作ったコードを載せますので、 どこが悪いのか、教えていただけないでしょうか。 よろしくお願いします。 package test01_frame; import java.awt.*; import javax.swing.*; public class TestFrame extends JFrame { Image bgimage; JPanel jp01; TestFrame() { super(); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); setSize( 384, 576 ); setLocationRelativeTo( null ); bgimage = new ImageIcon( "images/image01.jpg").getImage(); repaint(); //コメントアウトした部分がわからない箇所です。 //jp01 = new JPanel(); //jp01.setPreferredSize( new Dimension( 360, 50 )); //jp01.setBackground(Color.RED); //add( jp01 ); //jp01.setLocation( new Point( 10, 30 )); setVisible( true ); } public void update( Graphics g ) { paint( g ); } public void paint( Graphics g ) { g.drawImage( bgimage, 0, 0, null ); } /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ new TestFrame(); } }

    • ベストアンサー
    • Java
  • JFrame の再表示を禁止したい。

    親ウィンドウのボタンを押して、子ウインドウが表示される仕組みなのですが、1 つ表示した後は、 表示させないようにしたいと考えコードを組みましたが、以下コードでは、null 例外が出てしまいます。 良い方法はありませんでしょうか? みなさん、どうぞよろしくお願い致します。 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class FramesTest { public static void main(String[] args) { JFrame frameMain = new JFrame("Main"); frameMain.setSize(256, 128); frameMain.getContentPane().add( new BT() ); frameMain.setVisible(true); } } class BT extends JPanel implements ActionListener { /** * */ private static final long serialVersionUID = 1L; /*-------------------------* * Variables. * *-------------------------*/ static String cmdName; static JButton button; static JFrame subJFrame; /*-------------------------* * Methods. * *-------------------------*/ BT() { super( new BorderLayout() ); button = new JButton("button"); button.addActionListener(this); add( button ); setPreferredSize(new Dimension(320, 100)); } void createFrame() { subJFrame = new JFrame( "sub" ); subJFrame.setVisible(true); subJFrame.setSize(256, 128); } @Override public void actionPerformed(ActionEvent e) { cmdName = e.getActionCommand(); if ("button".equals(cmdName)) { if ( !subJFrame.isActive() ) { createFrame(); } } } }

    • ベストアンサー
    • Java

専門家に質問してみよう