简体   繁体   English

向Java Swing中的JPanel添加更多组件后,Repaint()无法正常工作

[英]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. 我从Java开始,想要制作一个简单的Pong游戏,以了解在Java中显示内容的方式。 I have created 2 classes that both extend JPanel and call the repaint() function every 16.6 milliseconds. 我创建了两个类,它们都扩展了JPanel并每隔16.6毫秒调用一次repaint()函数。 I added both to a JPanel which I added to the frame, but only the component I added first displays. 我将两者都添加到我添加到框架的JPanel中,但是仅显示我首先添加的组件。

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. 我尝试在两个类中的repaint() revalidate()之后repaint() revalidate() ,并确保Timer实际起作用,并且实际上调用了它的actionPerformed()方法。

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) (当然,我省略了诸如@Override或unseccaryary之类的东西来缩短代码)

This code only paints the Player, altough I want it to display all the components of mainPanel . 该代码仅绘制Player,尽管我希望它显示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: 我不得不将其拆分为3个文件,因为我喜欢匿名类:

Main.java 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. Player类的paintComponent()方法中,每次都绘制完全相同的Rectangle 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? 您期望Player做什么? 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 ? 您是否看过Oracle Java教程中名为“ 如何使用Swing计时器 ”的课程

EDIT 编辑

I see now that Player hides Ball , because of the default layout manager of JPanel . 现在我看到Player隐藏了Ball ,这是因为JPanel的默认布局管理器。 The below code is essentially the code you posted but I set GridLayout as the layout manager for mainPanel . 以下代码本质上是您发布的代码,但是我将GridLayout设置为mainPanel的布局管理器。 Also, a java source code file may contain more than one class but exactly one class must be public . 同样,一个Java源代码文件可能包含多个类,但恰好一个类必须是public Hence in the below code only class Main is public . 因此,在下面的代码中,仅Main类是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... 这是GUI的屏幕截图...

主要

I just realized that if I extend my window manually, the second JPanel shows up under the one responsible for the Player! 我只是意识到,如果我手动扩展窗口,第二个JPanel会显示在负责Player的一个下面! This means that I'll need to set the Panels position somehow, right? 这意味着我需要以某种方式设置面板的位置,对吗?

@Abra @阿布拉

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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