简体   繁体   中英

Repaint() does not work after adding more components to JPanel in Swing, Java

I am starting with Java and want to make a simple pong game to get into the ways of displaying stuff in java. I have created 2 classes that both extend JPanel and call the repaint() function every 16.6 milliseconds. I added both to a JPanel which I added to the frame, but only the component I added first displays.

I've tried to revalidate() after repaint() in both classes and made sure that the Timer actually works and that it's actionPerformed() method is actually called.

This is the main method:

public class Main {
  public static void main(String[] args){
    JFrame frame = new JFrame("Pong");
    //...
    JPanel mainPanel = new JPanel();

    mainPanel.add(new Player());
    mainPanel.add(new Ball(frameWidth/2, frameHeight/2 -40));

    frame.add(mainPanel);
  }
}

This is the important code for the classes (It's basically the same for both of them):

public class Player extends JPanel {

  public Player(){
    setPreferredSize(new Dimension(Main.frameWidth, Main.frameHeight));
    setBackground(Color.BLACK);

    new Timer(1000/60, new ActionListener(){
      public void actionPerformed(ActionEvent e){
        update();
        repaint();
      }
    }).start();
  }
//...
  public void paintComponent(Graphics g){
    super.paintComponent(g);

    g.setColor(Color.WHITE);
    g.fillRect(x, y, width, height);
  }
}

(Of coure I left things like @Override or unneseccary functions out to shorten the code)

This code only paints the Player, altough I want it to display all the components of mainPanel .

This is an example that you can (hopefully) run. I had to split it up into 3 files, since I suck at anonymus classes:

Main.java

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

  public static void main(String[] args){
    JFrame frame = new JFrame("Pong");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 800);

    JPanel mainPanel = new JPanel();

    mainPanel.add(new Player());
    mainPanel.add(new Ball());

    frame.add(mainPanel);

    frame.setVisible(true);
  }
}
///////
Player.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Player extends JPanel{
  private int x = 20, y = 300, width = 20, height = 100;
  public Player(){
    setPreferredSize(new Dimension(800, 800));
    setBackground(Color.BLACK);

    new Timer(1000/60, new ActionListener(){
      @Override
      public void actionPerformed(ActionEvent e){
        repaint();
      }
    }).start();
  }


  @Override
  public void paintComponent(Graphics g){
    super.paintComponent(g);

    g.setColor(Color.WHITE);
    g.fillRect(x, y, width, height);
  }
}
//////
Ball.java
//////
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Ball extends JPanel{
  private int x = 20, y = 300, width = 20, height = 100;
  public Ball(){
    setPreferredSize(new Dimension(800, 800));
    setBackground(Color.BLACK);
    new Timer(1000/60, new ActionListener(){
      @Override
      public void actionPerformed(ActionEvent e){
        repaint();
      }
    }).start();
  }

  @Override
  public void paintComponent(Graphics g){
    super.paintComponent(g);

    g.setColor(Color.WHITE);
    g.fillRect(x, y, width, height);
  }
}

In method paintComponent() of class Player , you paint the exact same Rectangle each time. In order to achieve animation, each time you paint the rectangle you need to change either its size or location or both. What do you expect the Player to do? Should it move up and down along the left edge of the window? Have you seen the lesson entitled How to Use Swing Timers which is part of Oracle 's Java Tutorial ?

EDIT

I see now that Player hides Ball , because of the default layout manager of JPanel . The below code is essentially the code you posted but I set GridLayout as the layout manager for mainPanel . Also, a java source code file may contain more than one class but exactly one class must be public . Hence in the below code only class Main is public .

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Pong");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel mainPanel = new JPanel(new GridLayout(0, 2));
        mainPanel.add(new Player());
        mainPanel.add(new Ball());
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}

class Player extends JPanel {

    public Player() {
        setBorder(BorderFactory.createLineBorder(Color.RED, 2, false));
        setPreferredSize(new Dimension(800, 800));
        setBackground(Color.BLACK);

        new Timer(1000 / 60, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint();
            }
        }).start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.WHITE);
        g.fillRect(20, 100, 20, 100);
    }
}

class Ball extends JPanel {

    public Ball() {
        setBorder(BorderFactory.createLineBorder(Color.CYAN, 2, false));
        setPreferredSize(new Dimension(800, 800));
        setBackground(Color.BLACK);
        new Timer(1000 / 60, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint();
            }
        }).start();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.WHITE);
        g.fillRect(300, 300, 10, 10);
    }
}

And here is a screen capture of the GUI...

主要

I just realized that if I extend my window manually, the second JPanel shows up under the one responsible for the Player! This means that I'll need to set the Panels position somehow, right?

@Abra

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM