JAVA - 无法在 JPanel 上绘制组件(也是 Runnable 和 KeyListener)
Posted
技术标签:
【中文标题】JAVA - 无法在 JPanel 上绘制组件(也是 Runnable 和 KeyListener)【英文标题】:JAVA - Can't paint a component (which is also a Runnable and KeyListener) on JPanel 【发布时间】:2014-12-29 09:10:10 【问题描述】:这些是我正在为一个使用 Java 和图形的简单游戏编写的类
主要:
import javax.swing.*;
import java.awt.*;
public class FrameTest extends JFrame
public FrameTest()
setSize(800,600);
setVisible(true);
public static void main(String[] args)
FrameTest frame = new FrameTest();
GamePanel panel = new GamePanel();
frame.add(panel);
面板测试:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PanelTest extends JPanel
private PlayerTest playerRunnable;
private Thread playerThread;
public PanelTest()
setSize(800,600);
playerRunnable = new PlayerTest();
playerThread = new Thread(playerRunnable);
//New
setLayout(new BorderLayout());
add(playerRunnable, BorderLayout.NORTH);
public void paintComponent(Graphics g)
super.paintComponent(g);
setBackground(Color.red);
它只是创建了一个具有红色背景的面板(我这样做是为了查看paintComponent() 是否适用于这项工作,它实际上是否有效)。
玩家测试:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import javax.swing.JComponent;
public class PlayerTest extends JComponent implements Runnable, KeyListener
public int x;
public int y;
private int speed;
public PlayerTest()
speed = 10;
x = 800/2;
y = 600/4;
addKeyListener(this);
setFocusable(true);
public void run()
while(true)
//New
public Dimension getPreferredSize()
return new Dimension(30,30);
public void paintComponent(Graphics g)
g.setColor(Color.BLUE);
g.fillRect(x, y, 30, 30);
public void keyReleased(KeyEvent e)
public void keyTyped(KeyEvent e)
public void keyPressed(KeyEvent e)
if(e.getKeyCode() == KeyEvent.VK_LEFT)
//Spostamento a sinistra player
move(speed*-1);
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
//Spostamento a destra player
move(speed);
if(e.getKeyCode() == KeyEvent.VK_SPACE)
//Lancio bomba
public void move(int s)
if (s < 0)
if(x-s > 0)
x += s;
System.out.println("[PLAY] move left, x: " + x);
repaint();
else
if(x+s < 800)
x += s;
System.out.println("[PLAY] move right, x: " + x);
repaint();
问题来了。这个类是一个 Runnable(用于动画)、一个 KeyListener(用于玩家移动)和一个 JComponent(用于显示玩家的图像,现在假设它是一个矩形) 我已经在 Panel 类中添加了这个组件,但是如果我尝试绘制它,它不会显示出来。我不明白为什么。纠结了这么久,终于决定在这里问一个问题。
【问题讨论】:
【参考方案1】:我发现您的代码存在一些问题,但最大的直接问题是您的 PlayerTest 组件没有设置首选大小,因此它的大小为 [1, 1],因此根本看不到。为其容器 PanelTest 提供一个 BorderLayout,以便 PlayerTest 组件填充其容器。
其他问题:
不要设置组件的大小。如果必须,请覆盖getPreferredSize()
,并让它为您的 GUI 返回最佳维度。这将更适合您的布局管理器。
请务必使用布局管理器,例如上面提到的 BorderLayout,以便您的 GUI 在需要时展开并放置在需要去的地方。
考虑使用 Swing 计时器而不是线程和空的 run()
方法,因为它更易于使用并保证您的代码是 Swing 线程安全的。
避免使用 KeyListener,而是使用 Key Binding,因为它们在组件焦点问题方面更易于使用。
例如:How to make an image move while listening to a keypress in Java.
在您的 JPanel 周围放置一个边框,您会发现它的大小等于 GUI 的宽度,但只有 30 磅高,因为您将其 preferredSize 限制为 30 x 30,但试图在其中绘制一些东西远远超出此范围,因此绘图组件不足以显示您的绘图。我将通过使 Player 类不从 Swing 组件扩展,而是使其成为一个 logical 类,一个知道如何绘制自身的类来构造不同的东西。我会让主 JPanel 成为绘图 JPanel,并给它一个 Player 对象来移动和显示。
例如,此代码显示并移动一个正方形,但仅在按右箭头时向右移动:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyAnimationTest extends JPanel
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final Color BG = Color.RED;
private static final int TIMER_DELAY = 15;
public static final int X_STEP = 5;
private MyPlayer player = new MyPlayer(PREF_W / 2, PREF_H / 4);
private boolean right = false;
private Timer timer = new Timer(TIMER_DELAY, new TimerListener());
public MyAnimationTest()
setBackground(BG);
setUpKeyBindings();
timer.start();
private void setUpKeyBindings()
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = getInputMap(condition);
ActionMap actMap = getActionMap();
KeyStroke rightArrowDownStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
KeyStroke rightArrowUpStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true);
inMap.put(rightArrowDownStroke, rightArrowDownStroke.toString());
inMap.put(rightArrowUpStroke, rightArrowUpStroke.toString());
actMap.put(rightArrowDownStroke.toString(), new RightMoveAction(true));
actMap.put(rightArrowUpStroke.toString(), new RightMoveAction(false));
@Override
public Dimension getPreferredSize()
if (isPreferredSizeSet())
return super.getPreferredSize();
return new Dimension(PREF_W, PREF_H);
@Override
protected void paintComponent(Graphics g)
super.paintComponent(g);
player.draw(g);
private class RightMoveAction extends AbstractAction
private boolean move;
public RightMoveAction(boolean move)
this.move = move;
@Override
public void actionPerformed(ActionEvent e)
right = move;
private class TimerListener implements ActionListener
@Override
public void actionPerformed(ActionEvent e)
if (right)
int newX = player.getX() + X_STEP;
player.setX(newX);
repaint();
private static void createAndShowGui()
MyAnimationTest mainPanel = new MyAnimationTest();
JFrame frame = new JFrame("My Animation");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
public void run()
createAndShowGui();
);
/**
* A logical class that does not extend a Swing component
*
* @author Pete
*
*/
class MyPlayer
public static final Color COLOR = Color.blue;
public static final int WIDTH = 30;
private BufferedImage sprite = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB);
private int x;
private int y;
public MyPlayer(int x, int y)
this.x = x;
this.y = y;
Graphics g = sprite.getGraphics();
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, WIDTH);
g.dispose();
public int getX()
return x;
public void setX(int x)
this.x = x;
public int getY()
return y;
public void setY(int y)
this.y = y;
public void draw(Graphics g)
g.drawImage(sprite, x, y, null);
【讨论】:
感谢您的回答。不过,如果我覆盖getPreferredSize()
,我还看不到绘制的组件。我还不能使用 Swing Timer,因为我们是为学校做的,而且我们只是在 Thread 段落上。编辑:我会尝试使用容器并报告。
@sonnhy:魔鬼在细节中。考虑editing your question 并在您当前的文本和代码下方添加您最新的代码尝试。
我可能不明白您的回答的真正含义,或者程序无法正常工作:|无论如何感谢帮助。
@sonnhy:见编辑回答。您正在绘制一个 30 x 30 的组件(实际上,因为它被放置在 BorderLayout.NORTH 中,它确实水平拉伸),但在这些边界之外绘制得很好,因此什么也看不到。
非常感谢您的支持。以上是关于JAVA - 无法在 JPanel 上绘制组件(也是 Runnable 和 KeyListener)的主要内容,如果未能解决你的问题,请参考以下文章