JFrame 不响应 setVisible() 和 dispose()
JFrame not responding to setVisible() and dispose()
我正在创建一个 "Snake" 游戏作为家庭作业,我花了几个小时搜索所有可能的方法来关闭 JFrame,但没有得出结论。我启动程序创建一个带有背景图像和菜单的 JFrame,仅此而已。当我单击 "Start game" 按钮 (JMenuItem) 时,它会打开一个带有线程的新 JFrame 来玩游戏。我的问题是第一个 JFrame 无论如何都没有关闭。我尝试使用 these solutions and these and these 但 JFrame 仍然存在。看起来他听的唯一命令是作为 DefaultCloseOperation 的 "EXIT_ON_CLOSE",甚至 "DISPOSE_ON_CLOSE" 都不起作用。这是我的 SnakeFrame class:
package snake;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
/**
*
* @author Giacomo
*/
public class SnakeFrame extends Snake{
protected JMenuItem start = new JMenuItem("Start game");
public void pullThePlug(final SnakeFrame frame) {
/*// this will make sure WindowListener.windowClosing() et al. will be called.
WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
// this will hide and dispose the frame, so that the application quits by
// itself if there is nothing else around.
frame.setVisible(false);
frame.dispose();*/
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentHidden(ComponentEvent e) {
((JFrame)(e.getComponent())).dispose();
}
});
}
public int game(final SnakeFrame frame,final JFrame gameFrame){
short game_ok=0;
try{
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GameThread gamethread = new GameThread(frame,gameFrame);
gamethread.start();
pullThePlug(frame);
}
});
}
catch(Exception e){
game_ok=1;
}
return game_ok;
}
//-----------Frame initialization with relative Listeners and Events.---------\
public SnakeFrame(){
JFrame frame= new JFrame("Le Snake");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
frame.setBounds(((int)larghezza/4),((int)altezza/4),800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
ImageIcon icon = new ImageIcon("C:\Users\Giacomo\Documents"
+ "\NetBeansProjects\Snake\src\res\Snake-icon.png");
frame.setIconImage(icon.getImage());
frame.setResizable(false);
frame.setLayout(new GridLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
menuBar.setBounds(1, 1, frame.getWidth(),frame.getHeight()/25);
JMenuItem close = new JMenuItem("Exit");
close.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(start);
menu.add(close);
frame.setJMenuBar(menuBar);
try {
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read
(new File("C:\Users\Giacomo\Documents\NetBeansProjects\"
+ "Snake\src\res\default.png")))));
} catch (IOException e) {
System.out.println("Exception with the background image.");
}
frame.pack();
}
//-------------------------Frame initialization ended.-----------------------\
}
这里是游戏线程的代码(目前):
package snake;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
/**
*
* @author Giacomo
*/
public class GameThread extends Thread implements Runnable{
private final SnakeFrame frame;
private final JFrame gameFrame;
public GameThread(final SnakeFrame f,final JFrame gF){
this.frame = f;
this.gameFrame = gF;
}
@Override
public void run(){
System.out.println("Game Thread started.");
final Label[][] griglia = new Label[50][50];
final Container container = new Container();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
gameFrame.setVisible(true);
gameFrame.setBounds(((int)larghezza/4),((int)altezza/4),
800, 600);
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon icon = new ImageIcon("C:\Users\Giacomo\Documents"
+ "\NetBeansProjects\Snake\src\res\Snake-icon.png");
gameFrame.setIconImage(icon.getImage());
gameFrame.setResizable(false);
gameFrame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e){
//Just to be sure he dies.
gameFrame.dispose();
frame.dispose();
System.exit(0);
}
});
gameFrame.setLayout(new GridLayout(50,50));
for(int i=0;i<50;i++){
for(int j=0;j<50;j++){
griglia[i][j] = new Label();
griglia[i][j].setBackground(Color.BLACK);
container.add(griglia[i][j]);
}
}
gameFrame.add(container);
}
}
我是不是忘记了什么?有人有想法吗?抱歉,如果我的代码不好,但我在学校学习 :P 我正在使用 NetBeans 8.0.2。感谢大家。
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++
编辑:
我现在已经解决了大部分问题,这里主要是:
public static void main(String[] args) {
final SnakeFrame frame = new SnakeFrame();
short isGameOk;
isGameOk =(short)frame.game(frame);
if(isGameOk==1)
System.err.println("Game Error!");
}
而这里是 SnakeFrame class ("fixed"):
public class SnakeFrame extends Snake{
private final JMenuItem start = new JMenuItem("Start game");
private final BackgroundPanel defaultpanel;
public int game(final SnakeFrame frame){
short game_ok=0;
try{
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
defaultpanel.setVisible(false);
JPanel panel = new JPanel();
JLabel[][] griglia = new JLabel[50][50];
panel.setLayout(new GridLayout(50,50));
for(int i=0;i<50;i++){
for(int j=0;j<50;j++){
griglia[i][j] = new JLabel();
griglia[i][j].setBackground(Color.BLACK);
panel.add(griglia[i][j]);
}
}
frame.add(panel);
griglia[45][30].setIcon(new ImageIcon
("src\res\sneikhead.png"));
panel.setVisible(true);
}
});
}
catch(Exception e){
game_ok=1;
}
return game_ok;
}
//-----------Frame initialization with relative Listeners and Events.---------\
public SnakeFrame(){
JFrame frame= new JFrame("Le Snake");
ImageIcon imm = new ImageIcon(getClass().getResource
("/res/default.png"));
Image background = imm.getImage();
defaultpanel = new BackgroundPanel(background, BackgroundPanel.ACTUAL,
1.0f, 0.5f);
frame.add(defaultpanel);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
frame.setBounds(((int)larghezza/4),((int)altezza/4),800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon imageIcon = new ImageIcon(getClass().getResource("/res/Snake-icon.png"));
Image icon = imageIcon.getImage();
frame.setIconImage(icon);
frame.setResizable(false);
frame.setLayout(new GridLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
menuBar.setBounds(1, 1, frame.getWidth(),frame.getHeight()/25);
JMenuItem close = new JMenuItem("Exit");
close.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(start);
menu.add(close);
frame.setJMenuBar(menuBar);
frame.pack();
}
//-------------------------Frame initialization ended.-----------------------\
}
我现在可以使用 defaultpanel.setVisible(false) 更改 SnakeFrame 的背景;但是即使我将其设置为真,也看不到应该显示的充满黑色标签的面板。我怎样才能让它可见?谢谢。
一些一般性评论:
为什么要创建第二个框架?通常一个游戏是在自己的框架内进行的?您有一个允许您更改游戏选项的菜单,这是通过显示模态 JDialog 来完成的。然后你有一个 "Start" 按钮,通过将面板添加到现有框架来启动游戏。
不要在框架上使用 ComponentListener。无需处理 componentHidden.
为什么会有game()
方法?我什至没有在您的代码中看到您调用该方法的位置。只需将 actionListener 添加到 class 的构造函数中的“开始”菜单项。将菜单项的创建和 actionListener 的分配保持在同一代码块中,这样我们就不需要遍历 class 来查找组件的所有相关属性。
When I click on the "Start game" button (JMenuItem) it opens a new JFrame with a thread to play the game.
这是错误的。你不应该开始一个单独的线程。所有 Swing 组件都应该在事件调度线程 (EDT) 上创建。所以基本上代码应该只从 ActionListener 中调用,因为所有事件代码都在 EDT 上执行。
It looks like the only command he listens to is the "EXIT_ON_CLOSE" as DefaultCloseOperation, not even the "DISPOSE_ON_CLOSE" is working.
这些是您为框架设置的属性。然后,当用户单击框架 top/right 处的 "X" 按钮时,框架将根据 属性 关闭。当您直接调用 frame.dispose() 或 System.exit() 时,这些属性无效。
GameThread gamethread = new GameThread(frame,gameFrame);
为什么要将框架传递给另一个 class?如果您的目标是关闭原始框架。然后在创建另一个框架后关闭此处的框架。事实上,您为什么还要在这里引用 "gameFrame"。如果您有另一个 class 创建框架的组件,它也应该创建框架。
pullThePlug(frame);
此代码不执行任何操作。您正在尝试关闭框架后调用此方法。
总的来说,由于代码不完整,我无法理解您的逻辑。但是,作为一般规则,应用程序应该只包含一个 JFrame。 Hiding/showing多帧不是体验用想看。当新游戏开始时,您应该只刷新现有框架的内容窗格。
我正在创建一个 "Snake" 游戏作为家庭作业,我花了几个小时搜索所有可能的方法来关闭 JFrame,但没有得出结论。我启动程序创建一个带有背景图像和菜单的 JFrame,仅此而已。当我单击 "Start game" 按钮 (JMenuItem) 时,它会打开一个带有线程的新 JFrame 来玩游戏。我的问题是第一个 JFrame 无论如何都没有关闭。我尝试使用 these solutions and these and these 但 JFrame 仍然存在。看起来他听的唯一命令是作为 DefaultCloseOperation 的 "EXIT_ON_CLOSE",甚至 "DISPOSE_ON_CLOSE" 都不起作用。这是我的 SnakeFrame class:
package snake;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
/**
*
* @author Giacomo
*/
public class SnakeFrame extends Snake{
protected JMenuItem start = new JMenuItem("Start game");
public void pullThePlug(final SnakeFrame frame) {
/*// this will make sure WindowListener.windowClosing() et al. will be called.
WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
// this will hide and dispose the frame, so that the application quits by
// itself if there is nothing else around.
frame.setVisible(false);
frame.dispose();*/
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentHidden(ComponentEvent e) {
((JFrame)(e.getComponent())).dispose();
}
});
}
public int game(final SnakeFrame frame,final JFrame gameFrame){
short game_ok=0;
try{
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GameThread gamethread = new GameThread(frame,gameFrame);
gamethread.start();
pullThePlug(frame);
}
});
}
catch(Exception e){
game_ok=1;
}
return game_ok;
}
//-----------Frame initialization with relative Listeners and Events.---------\
public SnakeFrame(){
JFrame frame= new JFrame("Le Snake");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
frame.setBounds(((int)larghezza/4),((int)altezza/4),800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
ImageIcon icon = new ImageIcon("C:\Users\Giacomo\Documents"
+ "\NetBeansProjects\Snake\src\res\Snake-icon.png");
frame.setIconImage(icon.getImage());
frame.setResizable(false);
frame.setLayout(new GridLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
menuBar.setBounds(1, 1, frame.getWidth(),frame.getHeight()/25);
JMenuItem close = new JMenuItem("Exit");
close.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(start);
menu.add(close);
frame.setJMenuBar(menuBar);
try {
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read
(new File("C:\Users\Giacomo\Documents\NetBeansProjects\"
+ "Snake\src\res\default.png")))));
} catch (IOException e) {
System.out.println("Exception with the background image.");
}
frame.pack();
}
//-------------------------Frame initialization ended.-----------------------\
}
这里是游戏线程的代码(目前):
package snake;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
/**
*
* @author Giacomo
*/
public class GameThread extends Thread implements Runnable{
private final SnakeFrame frame;
private final JFrame gameFrame;
public GameThread(final SnakeFrame f,final JFrame gF){
this.frame = f;
this.gameFrame = gF;
}
@Override
public void run(){
System.out.println("Game Thread started.");
final Label[][] griglia = new Label[50][50];
final Container container = new Container();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
gameFrame.setVisible(true);
gameFrame.setBounds(((int)larghezza/4),((int)altezza/4),
800, 600);
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon icon = new ImageIcon("C:\Users\Giacomo\Documents"
+ "\NetBeansProjects\Snake\src\res\Snake-icon.png");
gameFrame.setIconImage(icon.getImage());
gameFrame.setResizable(false);
gameFrame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e){
//Just to be sure he dies.
gameFrame.dispose();
frame.dispose();
System.exit(0);
}
});
gameFrame.setLayout(new GridLayout(50,50));
for(int i=0;i<50;i++){
for(int j=0;j<50;j++){
griglia[i][j] = new Label();
griglia[i][j].setBackground(Color.BLACK);
container.add(griglia[i][j]);
}
}
gameFrame.add(container);
}
}
我是不是忘记了什么?有人有想法吗?抱歉,如果我的代码不好,但我在学校学习 :P 我正在使用 NetBeans 8.0.2。感谢大家。 ++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++ 编辑:
我现在已经解决了大部分问题,这里主要是:
public static void main(String[] args) {
final SnakeFrame frame = new SnakeFrame();
short isGameOk;
isGameOk =(short)frame.game(frame);
if(isGameOk==1)
System.err.println("Game Error!");
}
而这里是 SnakeFrame class ("fixed"):
public class SnakeFrame extends Snake{
private final JMenuItem start = new JMenuItem("Start game");
private final BackgroundPanel defaultpanel;
public int game(final SnakeFrame frame){
short game_ok=0;
try{
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
defaultpanel.setVisible(false);
JPanel panel = new JPanel();
JLabel[][] griglia = new JLabel[50][50];
panel.setLayout(new GridLayout(50,50));
for(int i=0;i<50;i++){
for(int j=0;j<50;j++){
griglia[i][j] = new JLabel();
griglia[i][j].setBackground(Color.BLACK);
panel.add(griglia[i][j]);
}
}
frame.add(panel);
griglia[45][30].setIcon(new ImageIcon
("src\res\sneikhead.png"));
panel.setVisible(true);
}
});
}
catch(Exception e){
game_ok=1;
}
return game_ok;
}
//-----------Frame initialization with relative Listeners and Events.---------\
public SnakeFrame(){
JFrame frame= new JFrame("Le Snake");
ImageIcon imm = new ImageIcon(getClass().getResource
("/res/default.png"));
Image background = imm.getImage();
defaultpanel = new BackgroundPanel(background, BackgroundPanel.ACTUAL,
1.0f, 0.5f);
frame.add(defaultpanel);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double larghezza = screenSize.getWidth();
double altezza = screenSize.getHeight();
frame.setBounds(((int)larghezza/4),((int)altezza/4),800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon imageIcon = new ImageIcon(getClass().getResource("/res/Snake-icon.png"));
Image icon = imageIcon.getImage();
frame.setIconImage(icon);
frame.setResizable(false);
frame.setLayout(new GridLayout());
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
menuBar.setBounds(1, 1, frame.getWidth(),frame.getHeight()/25);
JMenuItem close = new JMenuItem("Exit");
close.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(start);
menu.add(close);
frame.setJMenuBar(menuBar);
frame.pack();
}
//-------------------------Frame initialization ended.-----------------------\
}
我现在可以使用 defaultpanel.setVisible(false) 更改 SnakeFrame 的背景;但是即使我将其设置为真,也看不到应该显示的充满黑色标签的面板。我怎样才能让它可见?谢谢。
一些一般性评论:
为什么要创建第二个框架?通常一个游戏是在自己的框架内进行的?您有一个允许您更改游戏选项的菜单,这是通过显示模态 JDialog 来完成的。然后你有一个 "Start" 按钮,通过将面板添加到现有框架来启动游戏。
不要在框架上使用 ComponentListener。无需处理 componentHidden.
为什么会有
game()
方法?我什至没有在您的代码中看到您调用该方法的位置。只需将 actionListener 添加到 class 的构造函数中的“开始”菜单项。将菜单项的创建和 actionListener 的分配保持在同一代码块中,这样我们就不需要遍历 class 来查找组件的所有相关属性。
When I click on the "Start game" button (JMenuItem) it opens a new JFrame with a thread to play the game.
这是错误的。你不应该开始一个单独的线程。所有 Swing 组件都应该在事件调度线程 (EDT) 上创建。所以基本上代码应该只从 ActionListener 中调用,因为所有事件代码都在 EDT 上执行。
It looks like the only command he listens to is the "EXIT_ON_CLOSE" as DefaultCloseOperation, not even the "DISPOSE_ON_CLOSE" is working.
这些是您为框架设置的属性。然后,当用户单击框架 top/right 处的 "X" 按钮时,框架将根据 属性 关闭。当您直接调用 frame.dispose() 或 System.exit() 时,这些属性无效。
GameThread gamethread = new GameThread(frame,gameFrame);
为什么要将框架传递给另一个 class?如果您的目标是关闭原始框架。然后在创建另一个框架后关闭此处的框架。事实上,您为什么还要在这里引用 "gameFrame"。如果您有另一个 class 创建框架的组件,它也应该创建框架。
pullThePlug(frame);
此代码不执行任何操作。您正在尝试关闭框架后调用此方法。
总的来说,由于代码不完整,我无法理解您的逻辑。但是,作为一般规则,应用程序应该只包含一个 JFrame。 Hiding/showing多帧不是体验用想看。当新游戏开始时,您应该只刷新现有框架的内容窗格。