主要问题1):程序运行,并显示JFrame,但是在
JFrame 它仅显示最后添加的对象/组件框。事实并非如此
显示另一张。为什么?
You do
window.add(b1);
window.add(b2);
,
默认情况下JFrame
has BorderLayout
因此,当您这样做时,您将替换最后添加的框add(..)
.
主要问题2):据我了解,我需要布局管理器。为什么
如果我只想在框架上的特定 X,Y 处绘制(),我需要它吗?
如果您正在使用JPanel
s 作为游戏中的对象,这将是唯一使用的时间setLayout(null)
因为我们想要完全控制JPanel
s 放置。
主要问题3):JFrame显示出来,它只显示1个框(绿色的
无论你做什么,一个人都不会出现。不知道为什么)以及何时
确实移动了——它从另一边被抹掉了。此处:盒子运动
因为你你这样做g.fillRect(x,y,w,h)
, 它应该是g.fillRect(0,0,w,h)
其他问题:
1)我认为你遇到的一个主要问题是:
public class Box extends JPanel{
...
public void paint(Graphics g){
...
}
}
你应该覆盖paintComponent
of JPanel
,并记得打电话super.paintComponent(g)
作为重写方法中的第一次调用。
3)你应该覆盖getPreferredSize
of JPanel
并返回与图像或内容匹配的正确尺寸JPanel
4)不要打电话setSize
on JFrame
使用正确Layoutmanager
和/或覆盖getPreferredSize
必要的容器而不是简单地调用pack()
on JFrame
在将其设置为可见之前。
5)正如@MadProgrammer所说,请阅读Swing 中的并发 http://docs.oracle.com/javase/tutorial/uiswing/concurrency/但基本上所有 Swing 组件都应该通过 EDT 创建/操作SwingUtilities.inokeXXX
block.
6)这样做肯定是不好的:
while (true){
b1.update();
b2.update();
try {
Thread.sleep(200);
} catch (Exception e) {
// TODO: handle exception
}
}
因为您不仅创建了一个连续循环,而且还调用Thread.sleep
在您创建的 GUY 线程上,这似乎会冻结。看一下如何使用 Swing 定时器 http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html,另见this https://stackoverflow.com/questions/14074329/using-sleep-for-a-single-thread/14074427#14074427关于上述主题的类似问题。
以下是已实施上述修复的代码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Screen {
private JFrame window;
public static void main(String[] args) {
//creat UI on EDT
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Screen();
}
});
}
public Screen() {
window = new JFrame("Multiply components panel") {
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
};
window.setLayout(null);//only reason this is warrented is because its a gmae using JPanels as game objects thus we need full control over its placing
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//changed from DISPOSE to EXIT so Timers will be exited too
final Box b1 = new Box(10, 10, 50, 50, "box1");
final Box b2 = new Box(100, 100, 50, 50, "box2");
window.add(b1);
window.add(b2);
window.pack();
window.setVisible(true);
Timer timer = new Timer(200, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
b1.update();
b2.update();
}
});
timer.setInitialDelay(0);
timer.start();
}
}
class Box extends JPanel {
int x, y, w, h;
private String name;
public Box(int x, int y, int w, int h, String name) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.name = name;
setBounds(x, y, w, h);//let the Box class handle setting the bounds more elegant OOP
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(this.name.equalsIgnoreCase("box1"));
if (this.name.equalsIgnoreCase("box1")) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, w, h);
} else {
g.setColor(Color.GREEN);
g.fillRect(0, 0, w, h);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(w, h);
}
public void update() {
if (this.name.equalsIgnoreCase("box1")) {
x++;
} else {
y++;
}
this.setBounds(x, y, w, h);//set the new bounds so box may be updated
System.out.println("Current " + name + ": X: " + x + ", Y: " + y + ", W: " + w + ", H: " + h);
revalidate();
repaint();
}
}
最后看看我的教程/代码片段游戏开发循环、逻辑和碰撞检测 Java Swing 2D http://www.daniweb.com/software-development/java/code/444547/game-development-loop-logic-and-collision-detection-java-swing-2d.
它拥有启动简单 2D 游戏所需的一切,例如游戏循环、逻辑、像素碰撞检测、动画(即在多个精灵之间交换以创建精灵集的动画)等等,但根本区别在于它使用对象作为游戏实体,即一个类将保存要绘制的对象的所有所需信息,IMO,这就是游戏应该如何完成的,事情可能会变得图形密集,并且许多 JPanels 怀疑屏幕肯定会降低整体 FPS