

swingを使って簡単なゲームを作っているのですが、描画処理がどうもうまくいかなくて困っています。。。

並列処理を使ってコンポーネントをひたすらrepaintし続ける処理を書いたつもりなんですが、いろいろいじったりして何度試してみても一向にpaintComponent()が呼び出されません。

原因が分かる方がいれば、ぜひご教授願いたいです…

* * *

PlayView.java（一部抜粋）

[code]

    import java.awt.*;
    import java.swing.*;
    
    public class PlayView extends JPanel implements KeyListener, Runnable{
    
        public JPanel panel = new JPanel(); //全部のコンポ―ネントを乗せるJPanel
        public static JPanel[] lane = new JPanel[4];
        public JLabel[] judge = new JLabel[4];
        public JLabel combo = new JLabel();
        public Dimension panelsize = null;
    
    public PlayView() {
    
            for (int i = 0; i < 4; i++) { 
                lane[i] = new JPanel();
                judge[i] = new JLabel();
            }
    
            panel.setSize(800, 600);
            panel.setLayout(null);
    
            for (int i = 0; i < 4; i++) { //座標指定でコンポーネントを配置
                lane[i].setBounds(200 * i, 0, 200, 500);
                judge[i].setBounds(200 * i, 520, 200, 60);
                lane[i].setBackground(new Color(211,211,211));
                lane[i].setBorder(new EtchedBorder(EtchedBorder.RAISED));
                judge[i].setBorder(new EtchedBorder(EtchedBorder.RAISED));
                judge[i].setFont(new Font("Arial",Font.PLAIN,27));
                judge[i].setForeground(new Color(220,20,60));
                panel.add(lane[i]);
                panel.add(judge[i]);
            }
    
            this.panelsize = lane[0].getSize();
    
            panel.setBackground(new Color(135,206,235));
            panel.addKeyListener(this);
    
        }
    
    @Override
        public void run() {
            while (this.isVisible())  {
                panel.repaint();　//10msごとにpanelの再描画
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void paintComponent(Graphics g) {
            //System.out.println("paintComponent");
            //super.paintComponent(g);
            g.setColor(new Color(255, 255, 255));//211,211,211
            for (int i = 0; i < 4; i++) {
                g.fillRect(200 * i, 0, (int) this.panelsize.getWidth(), (int) this.panelsize.getHeight());
            }
            //座標をランダムに変えて画像を描画
            for(int i = 0; i < 4; i++){
    　　　　　  g.drawImage((new ImageIcon("hoge.png")).getImage(), (int)Math.random() * (int) this.panelsize.getWidth(), 
               (int)Math.random() * (int) this.panelsize.getHeight(), lane[i]);
            }
        }
    
        @Override
        public void keyPressed(KeyEvent arg0) {
        if (arg0.getKeyCode() == KeyEvent.VK_SPACE) { //spaceを押したらrun()呼び出し
              Thread thread = new Thread(this);
              thread.start(); //this.run()の中身実行？
        }
    }
    
[/code]

MainFrame.java

[code]

    import java.awt.*;
    import java.swing.*;
    
    public class MainFrame extends JFrame implements KeyListener {
        PlayView pv = new PlayView();
        public MainFrame() {
            this.add(pv.panel);
            pv.panel.setVisible(true);
            this.setBounds(200, 100, 800, 600);
            this.addKeyListener(pv);
        }
        public static void main(String[] args) {
            MainFrame f = new MainFrame();
            f.setDefaultCloseOperation(EXIT_ON_CLOSE);
            f.setVisible(true);
        }
    }
    
[/code]


CC BY-SA 4.0
2019-07-23T16:48:52.063
56850
2019-07-24T01:54:52.857
2019-07-23T16:54:10.037
3060
35216
question
java swing
repaint()を記述してもpaintComponent()が呼び出されません…


### 動くコード

**MainFrame.java**

[code]

    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.*;
    
    public class MainFrame extends JFrame {
        PlayView pv = new PlayView();
        public MainFrame() {
            this.add(pv.panel);
            pv.setVisible(true);
            this.setBounds(200, 100, 800, 600);
            this.addKeyListener(pv);
        }
        public static void main(String[] args) {
            MainFrame f = new MainFrame();
            f.setDefaultCloseOperation(EXIT_ON_CLOSE);
            f.setVisible(true);
        }
    }
    
[/code]

**PlayView.java**

[code]

    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.*;
    import javax.swing.border.EtchedBorder;
    
    public class PlayView extends JPanel implements KeyListener, Runnable {
    
        //public JPanel panel = this; //解法その2
        public JPanel panel = new JPanel(); //解法その1
        public static JPanel[] lane = new JPanel[4];
        public JLabel[] judge = new JLabel[4];
        public JLabel combo = new JLabel();
        public Dimension panelsize = null;
    
        public PlayView() {
    
            for (int i = 0; i < 4; i++) {
                lane[i] = new JPanel() {
                    @Override
                    protected void paintComponent(Graphics g) {
                        super.paintComponent(g);
                        Image img = new ImageIcon("hoge.png").getImage();
                        int x = (int)(Math.random() * getWidth());
                        int y = (int)(Math.random() * getHeight());
                        g.drawImage(img, x, y, img.getWidth(this), img.getHeight(this), this);
                    }
                };
                judge[i] = new JLabel();
            }
    
            panel.setSize(800, 600);
            panel.setLayout(null);
    
            for (int i = 0; i < 4; i++) { //座標指定でコンポーネントを配置
                lane[i].setBounds(200 * i, 0, 200, 500);
                judge[i].setBounds(200 * i, 520, 200, 60);
                lane[i].setBackground(new Color(211, 211, 211));
                lane[i].setBorder(new EtchedBorder(EtchedBorder.RAISED));
                judge[i].setBorder(new EtchedBorder(EtchedBorder.RAISED));
                judge[i].setFont(new Font("Arial", Font.PLAIN, 27));
                judge[i].setForeground(new Color(220, 20, 60));
                panel.add(lane[i]);
                panel.add(judge[i]);
            }
    
            this.panelsize = lane[0].getSize();
    
            panel.setBackground(new Color(135, 206, 235));
            panel.addKeyListener(this);
    
        }
    
        @Override
        public void run() {
            while (this.isVisible()) {
                //repaint();  //解法その2
                panel.repaint();  //解法その1
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void keyPressed(KeyEvent arg0) {
            if (arg0.getKeyCode() == KeyEvent.VK_SPACE) { //spaceを押したらrun()呼び出し
                Thread thread = new Thread(this);
                thread.start(); //this.run()の中身実行？
            }
        }
    
        @Override
        public void keyTyped(KeyEvent ke) {}
    
        @Override
        public void keyReleased(KeyEvent ke) {}
    }
    
[/code]

### 修正点

  1. `PlayView#run`メソッドで **PlayViewではなくpanelを**`repaint`する
  2. `lane`インスタンスに`repaint`を実装
  3. 全角スペースを半角スペースに変換
  4. 足りないimportを補完

### ポイント

  1. `PlayView`クラスは`JPanel`を継承していますが、`JPanel`として描画されません。  
中に入っている`panel`がその役目を担っていますので、`repaint`する対象を`panel`に書き換えると`paintComponent`が呼び出されます。

  2. `PlayView`クラスを`JPanel`として使う場合は、サンプルコードの解法その1を削除して解法その2のコメントを削除してみてください。
  3. `panel`の上に`lane`が乗っているので、その下に隠れている`panel`を描画しても隠れていて動きません。  
どの`lane`に何を描画するか細かく制御したい場合は、`lane`クラスを`JPanel`ではなく`LanePanel extends
JPanel`などの別クラスとして定義して、`PlayView`とパラメータを受け渡しすることをご検討ください。


CC BY-SA 4.0
2019-07-24T01:54:52.857
56853
2019-07-24T01:54:52.857
9820
56850
answer