我正在构建一个Java Virtual Pet游戏,当前菜单面板工作正常,按钮正在加载和运行,但是当我单击应该启动到GamePanel面板中的新游戏按钮时,会出现nullpointerException。
这是构建原始框架和要切换的Jpanel的主要类。
public class MainFrame extends JPanel {
public JPanel mainPanel;
public CardLayout cl;
private final GamePanel gamePanel;
private final MenuPanel menuPanel;
/**
* Constructs the main panel to be used to switch between panels.
*
*/
public MainFrame() {
// creates a new panel to add panels to.
cl = new CardLayout();
// panel to be used as a main switch.
mainPanel = new JPanel();
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
setBackground(Color.BLACK);
add(mainPanel);
gamePanel = new GamePanel();
menuPanel = new MenuPanel();
// sets layout
mainPanel.setLayout(cl);
mainPanel.add(menuPanel, "menuPanel");
mainPanel.add(gamePanel, "gamePanel");
}
public void changePanel(String name) {
cl.show(mainPanel, name);
}
/**
* Main frame used by the game.
*
* @param args
*/
public static void main(String[] args) {
MainFrame game = new MainFrame();
JFrame frame = new JFrame("Main Window");
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
}
}
这是我的MenuPanel类中的代码,应该访问changePanel()方法。
public class MenuPanel extends JPanel {
MainFrame mf;
public MenuPanel() {
this.mf = mf;
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
ImageIcon menuIcon = new ImageIcon("C:\\Programming\\NetBeansProjects\\PDCMain\\src\\Data\\the_menu_title2.png");
JLabel menuLbl = new JLabel();
menuLbl.setIcon(menuIcon);
JButton newGameBtn = new JButton("New Game");
JButton loadGameBtn = new JButton("Load Game");
JButton helpBtn = new JButton("Instructions");
JButton exitBtn = new JButton("Exit");
newGameBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("New Game");
mf.changePanel("gamePanel");
}
});
loadGameBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
helpBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showHelp();
}
});
exitBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.weightx = 0;
gc.weighty = 0.1;
gc.gridx = 0;
gc.gridy = 1;
add(menuLbl, gc);
gc.gridx = 0;
gc.gridy = 2;
add(newGameBtn, gc);
gc.gridx = 0;
gc.gridy = 3;
add(loadGameBtn, gc);
gc.gridx = 0;
gc.gridy = 4;
add(helpBtn, gc);
gc.gridx = 0;
gc.gridy = 5;
add(exitBtn, gc);
}
public void showHelp(){
String[] help = new String[100];
try {
BufferedReader br = new BufferedReader(new FileReader("instruct.txt"));
String line = "";
int i = 0;
while((line = br.readLine()) != null) {
help[i] = line;
i++;
}
JOptionPane.showMessageDialog(null, help);
} catch(IOException ex) {
System.err.println("IOException Error: " + ex.getMessage());
}
}
这是游戏面板
public class GamePanel extends JPanel{
private ButtonsPanel buttonsPanel;
private GraphicsPanel graphicsPanel;
private final JPanel gamePanel;
public GamePanel(){
super();
this._initGUI();
gamePanel = new JPanel();
Dimension size = getPreferredSize();
size.width = 600;
size.height = 600;
setPreferredSize(size);
setBackground(Color.RED);
}
private void _initGUI(){
this.buttonsPanel = new ButtonsPanel();
this.graphicsPanel = new GraphicsPanel();
this.setLayout(new BorderLayout());
this.add(buttonsPanel, BorderLayout.SOUTH);
this.add(graphicsPanel, BorderLayout.CENTER);
}
public void run(){
graphicsPanel.run();
}
}
这是我第一次尝试从头开始构建GUI并使用cardlayout。我看不到它将为空值分配的位置,因为在用于切换的主面板中声明了该面板,有什么想法吗?
最佳答案
花点时间看一下这段代码...
public static class MenuPanel extends JPanel {
MainFrame mf;
public MenuPanel() {
this.mf = mf;
基本上,您是将(
this
)mf
分配给this.mf
,但是由于mf
已经是null
,因此this.mf
将保持null
...您应该将
MainFrame
的引用传递给您的MenuPanel
现在,因为我讨厌将UI组件的引用传递给程序的其他部分,而这些组件应该对UI的其余部分一无所知,并且不要直接控制它们,所以我建议不要像这样传递
MainFrame
盲法。而是创建一个
interface
,它提供您希望允许MenuPanel
执行的功能(例如newGame
,loadGame
,showInstructions
,exit
),并允许实现此interface
(可能是MainFrame
)来处理然后,您可以将此接口的实例传递给
MenuPanel
...这将类暴露给不需要这些类功能的其他类,并解耦了代码,因此您可以将接口的任何旧实例传递给该类。无需重写代码的整个部分...更新了基本概念
从某种游戏控制器界面开始,例如...
public interface GameController {
public void newGame();
public void loadGame();
public void showInstructions();
public void exit();
}
这描述了可以针对此接口的实现执行的操作。
使用
MainFrame
并实现GameController
...public class MainFrame extends JPanel implements GameController {
//...
public void newGame() {
}
public void loadGame() {
}
public void showInstructions() {
}
public void exit() {
}
更改
MenuPane
以在构造时要求GameController
的实例...public class MenuPanel extends JPanel {
private GameController controller;
public MenuPanel(GameController gameController) {
this.controller = gameController;
//...
现在,当您处理用户交互时,您可以将请求传递给控制器。
newGameBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("New Game");
controller.newGame();
}
});
这样,
MenuPanel
不知道如何创建新游戏,它只是知道它将得到照顾...现在,您将需要更新
newGame
中的MainFrame
方法以执行某些操作,例如...public void newGame() {
// Setup the new game...
cl.show(mainPanel, "gamePanel");
}
这将所有责任与
GameController
的实现完全放在一起,以决定某些操作的发生方式,使过程脱钩,因此,如果将GameController
的实现更改为其他类,则不需要担心更新MenuPanel
,因为它只对进入GameController
... nice感兴趣;)