我有两个类(Sampling
和Stacker
)。 Sampling
类(我的Main类)是JFrame
的扩展,并具有JButton
和ActionListener
来打开Stacker
类。
问题是单击按钮时,Stacker
类将打开,但只有一个没有任何组件的框架。当我将main方法切换到Stacker
类时,该程序运行正常。问题是什么?
这是代码:Sampling
类:
public class Sampling extends JFrame implements ActionListener
{
private JButton openStacker;
Stacker st;
public Sampling()
{
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
dispose();
st = new Stacker();
}
public static void main (String args[])
{
new Sampling();
}
}
Stacker
游戏类:public class Stacker extends JFrame implements KeyListener
{
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5,5};
int layer = 19;
int deltax[] = {0,0};
boolean press = false;
boolean forward = true;
boolean start = true;
public Stacker()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton [m][n];
setLayout(new GridLayout(n,m));
for (int y = 0;y<n;y++)
{
for (int x = 0;x<m;x++)
{
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
this.addKeyListener(this);
this.setVisible(true);
go();
}
public void go()
{
int tmp = 0;
Component temporaryLostComponent = null;
do{
if (forward == true)
{
forward();
} else {
back();
}
if (deltax[1] == 10-length[1])
{
forward = false;
} else if (deltax[1] == 0)
{
forward = true;
}
draw();
try
{
Thread.sleep((long) time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}while(press == false);
if (layer>12)
{
time= 150-(iteration*iteration*2-iteration);
} else
{
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");
repeat();
}
last = deltax[1];
start = false;
go();
}
public int check()
{
if (start == true)
{
return length[1];
}
else if (last<deltax[1])
{
if (deltax[1]+length[1]-1 <= last+length[0]-1)
{
return length[1];
}
else
{
return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
}
}
else if (last>deltax[1])
{
return length[1]-Math.abs(deltax[1]-last);
}
else
{
return length[1];
}
}
public void forward()
{
deltax[0] = deltax[1];
deltax[1]++;
}
public void back()
{
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw()
{
for (int x = 0;x<length[1];x++)
{
b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0;x<length[1];x++)
{
b[x+deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat()
{
if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
{
dispose();
new Stacker();
}else{
System.exit(0);
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
press = true;
}
}
public void keyReleased(KeyEvent arg0)
{
}
public void keyTyped(KeyEvent arg0)
{
}
}
最佳答案
只是为了将我所有的评论都放入答案中,并给您一个开始的地方:
评论1:
取出go();
会看到这种情况。我测试了它,它将起作用。如果将其留在那里,甚至连相框的关闭按钮都卡住了。您正在使用while-> Thread.sleep垃圾阻止edt。您将需要进行一些重构。您很难编写代码,而且我也不知道您要做什么,所以我什至没有尝试过
评论2:
如果您想知道为什么仅在Stacker类中运行main时为什么它起作用,那可能是因为您在EDT之外运行它,
public static void main(String[] args) { new Stacker(); }
。当您单击该按钮时,操作将在EDT中执行,因此您的new Stacker()
将在EDT上运行。在这种情况下,EDT将被while循环阻塞。如果尝试从Stacker类运行该程序,但将其包装在SwingUtilities.invokeLater
中,您还将注意到该程序无法正常工作。不过,Swing程序应在EDT上运行。
评论2:阅读Concurrency with Swing的前几节
因此,您可以做的是在游戏循环中使用Swing计时器(在EDT上运行)。我所做的只是稍微重构了您的代码。它并没有按照您想要的方式运行,只是因为我并不真正了解您的代码的逻辑。所以我无法使它工作。不过,我所做的是将某些逻辑放入计时器中。
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
调用
go()
方法时,它只是通过调用timer.start()
来启动计时器。基本上,您需要了解的计时器是,每个滴答声(经过的毫秒数),都会调用actionPerformed
。因此,您可以使用该方法更新游戏状态,就像在每次迭代的while循环中所做的一样。花点时间浏览How to Use Swing Timers
为了使游戏正常运行,您仍然需要进行一些调整,但这应该可以帮助您抢先一步。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Sampling extends JFrame implements ActionListener {
private JButton openStacker;
Stacker st;
public Sampling() {
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
dispose();
st = new Stacker();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sampling();
}
});
}
}
class Stacker extends JFrame implements KeyListener {
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5, 5};
int layer = 19;
int deltax[] = {0, 0};
boolean press = false;
boolean forward = true;
boolean start = true;
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
public Stacker() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400, 580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton[m][n];
setLayout(new GridLayout(n, m));
for (int y = 0; y < n; y++) {
for (int x = 0; x < m; x++) {
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
JPanel panel = (JPanel)getContentPane();
panel.addKeyListener(this);
this.setVisible(true);
panel.requestFocusInWindow();
go();
}
public void go() {
int tmp = 0;
Component temporaryLostComponent = null;
timer.start();
if (layer > 12) {
time = 150 - (iteration * iteration * 2 - iteration);
} else {
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");
repeat();
}
last = deltax[1];
start = false;
//go();
}
public int check() {
if (start == true) {
return length[1];
} else if (last < deltax[1]) {
if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
return length[1];
} else {
return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
}
} else if (last > deltax[1]) {
return length[1] - Math.abs(deltax[1] - last);
} else {
return length[1];
}
}
public void forward() {
deltax[0] = deltax[1];
deltax[1]++;
}
public void back() {
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw() {
for (int x = 0; x < length[1]; x++) {
b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0; x < length[1]; x++) {
b[x + deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat() {
if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dispose();
new Stacker();
} else {
System.exit(0);
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("Pressed");
press = true;
}
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
注意
SwingUtilities.invokeLater
中的main
。这样便可以在EDT上启动程序。 Swing中的并发链接将为您提供更多信息。关于java - 使用JButton打开新的JFrame,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26072653/