无法在 JPanel 上绘制矩形
Can't draw rectangles on JPanel
我目前正在尝试学习更多关于 swing 绘画的知识,并且我正在创建一个小游戏,但我似乎被卡住了。我正在尝试将几个矩形(敌人)添加到 ArrayList,然后在 paintComponent()
方法中绘制它们,但它似乎不起作用。
这是我的敌人class
import utils.RandomUtils;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class Enemy
{
double x, y, w, h;
Shape enemy;
Toolkit tk = Toolkit.getDefaultToolkit();
double width = tk.getScreenSize().width;
double height = tk.getScreenSize().height;
RandomUtils utils = new RandomUtils();
public Enemy(int w, int h)
{
this.w = w;
this.h = h;
enemy = new Rectangle2D.Double(setX(), setY(), w, h);
}
private double setX()
{
return x = utils.randInt((int) w, (int) width);
}
private double setY()
{
return y = utils.randInt((int) h, (int) height);
}
public Shape getEnemy()
{
return enemy;
}
}
这是我的看板class
import players.Enemy;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
public class Board extends JPanel
{
int x, y, speed = 1, height = 25, width = 25;
public Board()
{
addControls();
}
public void addControls()
{
Action upAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
y = y - speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("W"), "Up Action");
getActionMap().put("Up Action", upAction);
Action downAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
y = y + speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("S"), "Down Action");
getActionMap().put("Down Action", downAction);
Action leftAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
x = x - speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("A"), "Left Action");
getActionMap().put("Left Action", leftAction);
Action rightAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
x = x + speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("D"), "Right Action");
getActionMap().put("Right Action", rightAction);
}
boolean enemiesDrawn = false;
java.util.List<Enemy> enemies = new ArrayList<>();
java.util.List<Shape> enemyShapes = new ArrayList<>();
public void setEnemies()
{
for(int enemyCount = 0; enemyCount < 15; enemyCount++)
{
System.out.println(enemyCount);
enemies.add(new Enemy(15, 15));
enemyShapes.add(enemies.get(enemyCount).getEnemy());
}
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.RED);
g.fillOval(x, y, width, height);
if(!enemiesDrawn)
{
setEnemies();
g2.setColor(Color.BLUE);
g2.setBackground(Color.BLUE);
enemyShapes.forEach(g2::draw);
enemiesDrawn = true;
}
}
}
实用程序class
import java.util.Random;
public class RandomUtils
{
public RandomUtils()
{
}
public int randInt(int min, int max)
{
Random rand = new Random();
return rand.nextInt((max - min) + 1) + min;
}
}
和主要class
import javax.swing.*;
public class MainFrame
{
JFrame mainFrame;
public MainFrame()
{
mainFrame = new JFrame("Game");
addComponents();
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainFrame.setLocationRelativeTo(null);
mainFrame.pack();
mainFrame.setVisible(true);
}
public void addComponents()
{
mainFrame.add(new Board());
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(MainFrame::new);
}
}
绘制椭圆形(玩家)效果很好,我似乎无法绘制列表中的敌人。 should/could 我该怎么做才能解决这个问题?
所以你的主要问题在这里...
if (!enemiesDrawn) {
setEnemies();
g2.setColor(Color.BLUE);
g2.setBackground(Color.BLUE);
System.out.println("...");
enemyShapes.forEach(g2::draw);
enemiesDrawn = true;
}
一旦paintComponent
被调用一次,敌人将不会再被绘制。 paintComponent
可能会被调用很多次(通常是快速连续调用),每次调用时,您都需要从头开始重新绘制组件的整个状态。
查看 Painting in AWT and Swing and Performing Custom Painting 了解有关 Swing 绘画工作原理的更多详细信息
观察结果...
这有点毫无意义...
mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainFrame.setLocationRelativeTo(null);
mainFrame.pack();
您正在将框架设置为最大化但随后试图压缩它?这可能会导致某些系统出现问题,因此请注意。
RandomUtils
应该创建 Random
的单个实例,因为它的工作方式,您 运行 有 Random
return 相同的值,以相同的顺序。你可以摆脱一个单身人士
public enum RandomUtils {
INSTANCE;
private Random rand = new Random();
public int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
}
在你的Enemy
中使用Toolkit
不是一个好主意,除了敌人对外界知之甚少之外,Toolkit
也不是最好的确定实际可视屏幕尺寸的选择,考虑到您的 window 有装饰并且桌面有任务栏之类的东西,这是 运行 您的一些敌人出现在屏幕上的风险
由于您的程序的工作方式,很难提出可以复制输出的建议。但基本上,您应该将所需的 location/size 传递给 Enemy
class.
的构造函数
您可以使用 ComponentListener
并监视 componentResized
方法,它首先稳定,然后您可以根据组件的当前大小创建敌人
我目前正在尝试学习更多关于 swing 绘画的知识,并且我正在创建一个小游戏,但我似乎被卡住了。我正在尝试将几个矩形(敌人)添加到 ArrayList,然后在 paintComponent()
方法中绘制它们,但它似乎不起作用。
这是我的敌人class
import utils.RandomUtils;
import java.awt.*;
import java.awt.geom.Rectangle2D;
public class Enemy
{
double x, y, w, h;
Shape enemy;
Toolkit tk = Toolkit.getDefaultToolkit();
double width = tk.getScreenSize().width;
double height = tk.getScreenSize().height;
RandomUtils utils = new RandomUtils();
public Enemy(int w, int h)
{
this.w = w;
this.h = h;
enemy = new Rectangle2D.Double(setX(), setY(), w, h);
}
private double setX()
{
return x = utils.randInt((int) w, (int) width);
}
private double setY()
{
return y = utils.randInt((int) h, (int) height);
}
public Shape getEnemy()
{
return enemy;
}
}
这是我的看板class
import players.Enemy;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
public class Board extends JPanel
{
int x, y, speed = 1, height = 25, width = 25;
public Board()
{
addControls();
}
public void addControls()
{
Action upAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
y = y - speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("W"), "Up Action");
getActionMap().put("Up Action", upAction);
Action downAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
y = y + speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("S"), "Down Action");
getActionMap().put("Down Action", downAction);
Action leftAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
x = x - speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("A"), "Left Action");
getActionMap().put("Left Action", leftAction);
Action rightAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
x = x + speed;
repaint();
}
};
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke("D"), "Right Action");
getActionMap().put("Right Action", rightAction);
}
boolean enemiesDrawn = false;
java.util.List<Enemy> enemies = new ArrayList<>();
java.util.List<Shape> enemyShapes = new ArrayList<>();
public void setEnemies()
{
for(int enemyCount = 0; enemyCount < 15; enemyCount++)
{
System.out.println(enemyCount);
enemies.add(new Enemy(15, 15));
enemyShapes.add(enemies.get(enemyCount).getEnemy());
}
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.RED);
g.fillOval(x, y, width, height);
if(!enemiesDrawn)
{
setEnemies();
g2.setColor(Color.BLUE);
g2.setBackground(Color.BLUE);
enemyShapes.forEach(g2::draw);
enemiesDrawn = true;
}
}
}
实用程序class
import java.util.Random;
public class RandomUtils
{
public RandomUtils()
{
}
public int randInt(int min, int max)
{
Random rand = new Random();
return rand.nextInt((max - min) + 1) + min;
}
}
和主要class
import javax.swing.*;
public class MainFrame
{
JFrame mainFrame;
public MainFrame()
{
mainFrame = new JFrame("Game");
addComponents();
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainFrame.setLocationRelativeTo(null);
mainFrame.pack();
mainFrame.setVisible(true);
}
public void addComponents()
{
mainFrame.add(new Board());
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(MainFrame::new);
}
}
绘制椭圆形(玩家)效果很好,我似乎无法绘制列表中的敌人。 should/could 我该怎么做才能解决这个问题?
所以你的主要问题在这里...
if (!enemiesDrawn) {
setEnemies();
g2.setColor(Color.BLUE);
g2.setBackground(Color.BLUE);
System.out.println("...");
enemyShapes.forEach(g2::draw);
enemiesDrawn = true;
}
一旦paintComponent
被调用一次,敌人将不会再被绘制。 paintComponent
可能会被调用很多次(通常是快速连续调用),每次调用时,您都需要从头开始重新绘制组件的整个状态。
查看 Painting in AWT and Swing and Performing Custom Painting 了解有关 Swing 绘画工作原理的更多详细信息
观察结果...
这有点毫无意义...
mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainFrame.setLocationRelativeTo(null);
mainFrame.pack();
您正在将框架设置为最大化但随后试图压缩它?这可能会导致某些系统出现问题,因此请注意。
RandomUtils
应该创建 Random
的单个实例,因为它的工作方式,您 运行 有 Random
return 相同的值,以相同的顺序。你可以摆脱一个单身人士
public enum RandomUtils {
INSTANCE;
private Random rand = new Random();
public int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
}
在你的Enemy
中使用Toolkit
不是一个好主意,除了敌人对外界知之甚少之外,Toolkit
也不是最好的确定实际可视屏幕尺寸的选择,考虑到您的 window 有装饰并且桌面有任务栏之类的东西,这是 运行 您的一些敌人出现在屏幕上的风险
由于您的程序的工作方式,很难提出可以复制输出的建议。但基本上,您应该将所需的 location/size 传递给 Enemy
class.
您可以使用 ComponentListener
并监视 componentResized
方法,它首先稳定,然后您可以根据组件的当前大小创建敌人