使用二进制序列化加载菜单



我正在用java做一个海战游戏,我用JMenubar创建了一个菜单,我希望能够保存和加载游戏。

我创建了一个实现ActionListener的类将它添加到我的菜单中的一个项目中,但它不起作用,这不会向我返回错误,但不会加载平台对象,我的加载功能是正确的,我测试了它。

package actionlistener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JFileChooser;
import Main.Plateau;
import interfaceGraphique.Fenetre;
import ioforme.IOPlateau;
public class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public Plateau plateau;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;

}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(fenetre);
if(retour==JFileChooser.APPROVE_OPTION){
try {

Plateau p = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setPlateau(p);
System.out.println(choix.getSelectedFile().getAbsolutePath());
fenetre.actualiserGrilleCible();
fenetre.actualiserMaGrille();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

我很快就写了这段代码,它运行得很好,但也有同样的问题。我有三个按钮;一个用于保存、加载和在控制台中显示人类对象,我可以放心保存。例如:我用人类("jean",10(启动程序(在主功能中(我保存。我退出了我的程序,我改变了人类("jean",50(当我按下加载按钮时我加载以前保存的文件然后我点击按钮在控制台中显示,它会显示我人类[jean,50]但我想要"人类[让,10]">

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.swing.*;

public class Main  {
public static class Human implements Serializable {
String name;
int age;
public Human(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String toString() {
return "Human [name=" + name + ", age=" + age + "]";
}

}

public static class ChargerActionListener implements ActionListener {
public Fenetre fenetre;
public ChargerActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;

}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showOpenDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {

Human h  = IOPlateau.lire(choix.getSelectedFile().getAbsolutePath());
fenetre.setHuman(h);
System.out.println(choix.getSelectedFile().getAbsolutePath());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}
public static class SauvegarderActionListener implements ActionListener {
public Fenetre fenetre;
public SauvegarderActionListener(Fenetre fenetre)
{
this.fenetre = fenetre;

}
public void actionPerformed(ActionEvent arg0) {
JFileChooser choix = new JFileChooser();
int retour=choix.showSaveDialog(null);
if(retour==JFileChooser.APPROVE_OPTION){
try {

IOPlateau.sauver(fenetre.getHuman(),choix.getSelectedFile().getAbsolutePath());
System.out.println(choix.getSelectedFile().getAbsolutePath());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}
public static class Fenetre extends JFrame {
private Human human;
Fenetre (Human human)
{
this.human = human;
this.setTitle("test");
this.setSize(1200,500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     
JButton save = new JButton ();
save.addActionListener(new SauvegarderActionListener(this));
JButton load = new JButton();
load.addActionListener(new ChargerActionListener(this));
JButton display = new JButton ();
JPanel panel = new JPanel (new GridLayout(1,3));
// Button for load and save !
panel.add(save);
panel.add(load);
panel.add(display);
this.setContentPane(panel);
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) 
{
System.out.println(human);
}
});
this.setVisible(true);
}
public void setHuman (Human human)
{
this.human = human;
}
public Human getHuman ()
{
return this.human;
}

}
public static class IOPlateau {
public static Human lire(String fileName) throws IOException {
Human h = null;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName));
try {
h = (Human) ois.readObject();
} catch (ClassNotFoundException cnfe) {
// erreur de lecture
} catch (EOFException eofe) {
//fin de fichier
}
ois.close();
return h;
}
public static void sauver(Human h, String fileName) throws IOException {
try {
// Recevoir le fichier 
File f = new File(fileName);
// Créer un nouveau fichier
// Vérifier s'il n'existe pas
if (f.createNewFile())
System.out.println("File created");
else
System.out.println("File already exists");
}
catch (Exception e) {
System.err.println(e);
}
ObjectOutputStream oos;
oos = new ObjectOutputStream(new FileOutputStream(fileName));
oos.writeObject(h);
oos.close();
}
}

public static void main(String[] args) {
Human human = new Human ("Jean",11);
Fenetre fenetre = new Fenetre(human);

}
}

问题出在与显示JButton关联的actionListener()方法中。由于类成员human与类Fenetre的构造函数中的参数同名,因此在构造函数代码中要访问成员(而不是参数(的任何位置,都需要使用this关键字对其进行限定。

以下是应该如何编写方法actionListener()

display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(Fenetre.this.human);
}
});

您需要Fenetre.this.human,因为您正在创建一个匿名的内部类,而human是封闭类的成员。

如果您至少使用Java 8,则可以将匿名内部类替换为lambda表达式,因为接口java.awt.event.ActionListener是一个函数接口,即只包含一个抽象方法的接口。这是用来替换匿名内部类的lambda表达式。

display.addActionListener(e -> System.out.println(this.human));

正如您所看到的,在lambda表达式中,您只需要编写this.human就可以访问类Fenetre的成员human

您是否正确地将ChargerActionListener添加到项目中:

.addActionListener(new ChargerActionListener(fenetre));

也可以尝试使用:

JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
int returnValue = jfc.showOpenDialog(null);

也许"null"作为"showOpenDialog"的参数会起作用。(我不知道围栏或平台应该是什么(

此外,可能只有对话框不会打开,但实际上正在调用Listener。

请通过运行类似(在"actionPerformed"中(的程序来检查:

System.out.println("Ok");

您的序列化代码运行良好。您的问题在于如何显示所获得的结果。你这样做:

public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(human);
}
});
// ....
}
// ....
}

System.out.println(human);调用引用的是传递给构造函数的参数,而不是类的字段,因此值永远不会更改。

如果您现在将代码更改为:

public static class Fenetre extends JFrame {
private Human human;
Fenetre(Human human) {
this.human = human;
// ....
display.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evenement) {
System.out.println(getHuman());
}
});
// ....
}
// ....
}

由于getHuman()返回实例字段human所持有的值,您将看到结果是正确的,human字段引用值实际上已经更改。

最新更新