java - 在 Java 的 Swing 中向 JPanel 添加更多组件后,Repaint() 不起作用
问题描述
我从 Java 开始,想制作一个简单的乒乓球游戏,以了解在 Java 中显示内容的方式。我创建了 2 个类,它们都扩展 JPanel 并repaint()
每 16.6 毫秒调用一次函数。我将两者都添加到了我添加到框架中的 JPanel 中,但只有我首先添加的组件才会显示。
我在这两个类中都尝试过,revalidate()
并repaint()
确保 Timer 确实有效并且它的actionPerformed()
方法实际上被调用了。
这是主要方法:
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);
}
}
这是类的重要代码(两者基本相同):
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);
}
}
(当然,我留下了诸如 @Override 或不必要的函数之类的东西来缩短代码)
此代码仅绘制播放器,尽管我希望它显示mainPanel
.
这是一个您可以(希望)运行的示例。我不得不把它分成 3 个文件,因为我很讨厌匿名类:
主.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);
}
}
解决方案
在paintComponent()
class 的方法中,您每次都Player
绘制完全相同的内容。Rectangle
为了实现动画效果,每次绘制矩形时都需要更改其大小或位置,或两者兼而有之。你期望它Player
做什么?它应该沿着窗口的左边缘上下移动吗?您是否看过Oracle的Java 教程中题为“如何使用 Swing 计时器”的课程?
编辑
我现在看到Player
隐藏Ball
了,因为JPanel
. 下面的代码本质上是您发布的代码,但我设置GridLayout
为mainPanel
. 此外,一个 java 源代码文件可能包含多个类,但只有一个类必须是public
. 因此,在下面的代码中,只有 classMain
是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);
}
}
这是GUI的屏幕截图......
推荐阅读
- ruby-on-rails - 将活动存储输出写入临时文件
- azure - Azure Artifacts - 需要创建组织范围的源
- javascript - 使用参数调用 PHP 中的特定函数
- excel - 应用程序定义或对象定义的错误(逗号)VBA
- c# - 有没有办法让客户端连接到现有的 WCF Web Http 服务而不使用 .Net Core 2 中的 WebHttpBinding?
- laravel - Laravel 反应认证脚手架
- regex - Laravel 中管理员和非管理员的路由区分
- python - 为什么我的权限被拒绝?蟒蛇熊猫
- r - 如何在R中拆分字符并计算相应的频率
- google-apps-script - 如何加快删除满足特定条件的行的 for 循环?