How do I save the state of my program? [duplicate] - java

This question already has answers here:
How can I save the state of my program and then load it?
(2 answers)
Closed 6 years ago.
For my program I have two buttons, "Add" and "Save". When I click "Add" a button is added to the JPanel. My question is, how do I save the current state of my program with all the buttons the user added? Do I use serialization?
Here is a snippet of my code:
public class saveButton
{
//JFrame and JPanels have been declared earlier
class ClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String str = JOptionPane.showInputDialog("Name of button");
JButton b = new JButton(str);
frame.add(b);
}
}
ActionListener addButtonClicked = new ClickListener();
b.addActionListener(addButtonClicked);
class ClickListenerTwo implements ActionListener
{
public void actionPerformed(ActionEvent f)
{
//save all of the program
}
}
}

You can only serialize (meaning straight Java serialization) if your object and every non-transient member within the class supports serialization. This is not always possible.
However, you could define your own configuration object that contains the necessary state information and save it whenever (could be just before closing app, could be every time the state changes, it's up to you) and serialization might be a way to do it

It depends on how you save it. You can write the state onto a file and then recover it from there by reading it. The number of buttons and the order etc. You have to decide on the format on how you want to save it too. For example you may want to store in one line
Save,JButton,imageSrc,xpos,ypos
So when you read that line and split on ',' you know that Save is the text, JButton is the class, etc.
Hope this helps

I would write my own file format rather than deal with the overhead of Java's serialization. This has the benefit of being more easily readable in other languages and of slightly better performance. Furthermore, as #MadProgrammer pointed out the Serialization of Swing object is not currently supported and will not be compatible with future releases:
Warning: Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage of
all JavaBeans™ has been added to the java.beans package. Please see
XMLEncoder.
(link)
Here is an example:
public void saveState(){
File stateFile = new File("./stateFile");
FileOutputStream fos = new FileOutputStream(stateFile);
DataOutputStream dos = new DataOutputStream(fis);
for(JButton button : jButtons){ //store the buttons in an arraylist when they are created (you could also iterate over the added components and use instanceof)
dos.writeUTF(button.getText());
}
dos.writeUTF("end"); //have some sort of end marker
dos.flush();
dos.close();
fos.flush();
fos.close()
}
public void loadState(){
File stateFile = new File("./stateFile");
FileInputStream fis = new FileInputStream(stateFile);
DataInputStream dis = new DataInputStream(fis);
String name;
while(!(name = dis.readUTF()).equals("end")){
add(new JButton(name));
}
fis.close();
}

Related

Java checkbox state in another class [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
How to pass actual checkbox state (true/false) from GUI class to another class? I want to run some part of code only if checkbox in GUI is selected. I guess it has to be if statement (highlithed part below) but i cant get it working.
public class csvtoxls {
public static void main() throws IOException {
//here you enter the path to your directory.
//for example: Path workDir = Paths.get("C:\\Users\\Kamil\Desktop\\csvtoxlspython\\Nowy folder (2)")
JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
jfc.setDialogTitle("Wybierz folder do konwersji: ");
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
jfc.setAcceptAllFileFilterUsed(false);
int returnValue = jfc.showSaveDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
if (jfc.getSelectedFile().isDirectory()) {
System.out.println("You selected the directory: " + jfc.getSelectedFile());
String z;
//#SuppressWarnings("deprecation")
Path workDir = jfc.getSelectedFile().toPath();
System.out.println(workDir);
//Path workDir = FileSystems.getDefault(jfc.getCurrentDirectory()).jfc.getCurrentDirectory();
//Path workDir = Paths.get(gui.pickPath(jfc));
File dirg = jfc.getSelectedFile();
//String str = dirg.getPath();
// ************* CODE WITH ISSUE *************
if TextAreaLogProgram.checkbox.isSelected() {
try {
Thread.sleep(5000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
String str = dirg.getPath();
delfiles td = new delfiles();
td.deleteFiles(str + "/", ".csv");
System.out.println("SUCCESS!");
msgbox.infoBox("SUCCES!", "CSVtoXLS");
}
GUI class:
public class TextAreaLogProgram extends JFrame {
private JTextArea textArea;
private JButton buttonStart = new JButton("CONVERT");
private JButton buttonClear = new JButton("CLEAR");
private PrintStream standardOut;
public TextAreaLogProgram() {
super("CSVtoXLS");
JCheckBox checkbox = new JCheckBox();
add(checkbox);
checkbox.setText("Delete files");
checkbox.setSelected(true);
Your other class will need a method or constructor with a parameter to be able to accept the value from the other class
See Passing Information to a Method or a Constructor for more details
Other issues:
Your program structure needs to be redone completely. Right now your main method is much too large, meaning that you're doing too much within the static world and not using Java to its best OOPs advantage.
Before even thinking of creating the GUI, first create the non-GUI "model" classes that your program will need. Like all your classes, these should have minimal static fields and methods, and strive to follow object-oriented best practices
You've got a Thread.sleep within your GUI code, something that does not work well with Swing GUI's since this risks putting the entire GUI to sleep, making it non-responsive. If you want Swing delays, use a Swing Timer (google the excellent tutorial on this)
You're trying to check the checkbox as if it were a static field of the TextAreaLogProgram class. It's not a static field and in fact its not even a field of the class.
The fact that you're doing the above suggests that you would benefit greatly from studying introductory tutorials on Object-Oriented programming and Java -- you are putting the cart before the horse by trying to create a GUI before first understanding Java fundamentals. Again, you won't regret the effort expended doing this.
Whatever you do, don't make the JCheckBox a static field and try to access it this way. This will lead to spaghetti code and increased risk for bugs.
Instead, make it a non-static (instance) private field of the TextAreaLogProgram class, and give the class a getter method to allow other objects access to the JCheckgbox's state.
There's so much more that can be mentioned about your code and problem... but this will do for now.

Java serialisation and dealing with objects [duplicate]

This question already has an answer here:
Java hashset how to serialise multiple objects
(1 answer)
Closed 6 years ago.
I'm using the code below, to get data from a file saved on my desktop to input into the game that I'm making.
try {
FileInputStream saves = new FileInputStream("/Users/Prodigy958/Desktop/Hack_exeSaves.ser");
ObjectInputStream in = new ObjectInputStream(saves);
test = (player) in.readObject();
in.close();
saves.close();
} catch(IOException error) {
error.printStackTrace();
return;
} catch(ClassNotFoundException error) {
error.printStackTrace();
return;
}
There is also the section which takes the player object and inputs it into a file.
player realPlayer = new player();
realPlayer.name = newName;
realPlayer.gender = newGender;
realPlayer.hasStarted = false;
try {
FileOutputStream fileOut = new FileOutputStream("/Users/Prodigy958/Desktop/Hack_exeSaves.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(realPlayer);
out.close();
fileOut.close();
} catch(IOException i) {
i.printStackTrace();
}
The issue that I am having is that if you save more than one player data onto the file, it calls up errors because it takes all the data and turns it into one player object. Do you know an easy way I would be able to split up the data? I have thought about using multiple files to store each different object's data. I have also though about taking out the data and splitting it up into separate objects, and then working from there, however I don't know where to start on the second one.
As others have already suggested, use a Serializable implementation of java.util.Collection. (Most of the java.util collections--such as java.util.ArrayList and java.util.HashSet--are Serializable.) A collection of 0 or 1 elements shouldn't bother you (it's not relevant to the serialization of the collection) unless your game has other business requirements that care, but... in that case, that's far beyond the scope of this question, and for you to handle on your own.

Writing file when closing window

I'm writing a Restaurant Program.
When the user confirms his order, the order gets stored in an array of type order. Why? because when the user chooses to close the program, all orders get saved in a file with item's names and information about each item.
Also, every order object has an array of type item inside it!
Could you help me on how to write that file?
I know it'll be in the method processWindowEvent.
This is my try, i know that i should remove textArea.getText() but i don't know how to print all items, neither.
protected void processWindowEvent(WindowEvent e){
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
JOptionPane.showMessageDialog(this,"All operation have been saved ");
try{
outFile=new File("Orderslist.txt");
out=new FileOutputStream(outFile);
ob=new PrintWriter(out);}
catch(IOException M){M.getMessage(); }
for(int i=0;i<o2.length;i++){
if(o2[i]!=null){
if(o2[i].getCount()<=4)
ob.println(o2[i].toString()+"\n--------------\n"+textArea.getText()+"--------------\n"+"\nTotal: "+o2[i].getTotalPrice());
else if(o2[i].getCount()>4)
ob.println(o2[i].toString()+"\n--------------\n"+textArea.getText()+"--------------\n"+"\nTotal Price#: "+o2[i].getTotalPrice()+"\n\nDiscount 20%\n\n--------------\nTotal price#: "+(o2[i].getTotalPrice()-(o2[i].getTotalPrice()*0.2)));
}
}
In the constructor of your Widnow add this:
public Window() {
this.addWindowListener(new WindowAdapter(){
#Override
public void windowClosing(WindowEvent arg0) {
writeFile(textArea.getText()); //Call your method
System.exit(0);
}
});
...
}
For writing the file:
File file = new File("myFile.txt");
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write("Texto to write");
bw.close();
After ob.println() do ob.close(); or ob.flush();.
If you dont close the stream or flush the stream , nothing will be printed in your file.
Really this isn't the best design, you should write changes to the file immediately as they are made. The reason for this is that if the application closes for any other reason (power cut, task manager kill, crash, etc) then you don't want to lose the user's data. It would also be worth automatically backing up that file (for example copying it after startup) so if you corrupt the current session somehow you can revert.
To actually implement the saving you want to use a FileOutputStream of some sort but the exact implementation will vary a lot depending on the format that you want the data inside the stream. For example XML, JSON, plan text, binary serialization etc are all fairly easy but you need to pick one :)

JList only updating on first insertion

This is my first attempt at a decent GUI for a Java app and I needed to use JLists with custom ListModels in order to represent certain structures.
//The 2 below structures implement the ListModel interface, using an internal
//ArrayList, in order to be used as
//a model for 2 different JLists in my GUI.
private PropertyList propertiesList = new PropertyList();
private SelectedProperties selProperties = new SelectedProperties();
//and these are the two JLists they are the models for
private javax.swing.JList Properties_JList;
private javax.swing.JList SelectedProperties_JList;
Here I populate my first JList via a stream:
private void OpenFile_MenuItemActionPerformed(java.awt.event.ActionEvent evt) {
final JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(null);
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
this.Properties_JList.setModel(propertiesList);
this.propertiesList.AddFromFile(file);
} else {
//...
}
}
which happens to be working perfectly fine. I import a few entries by reading the file and they are all displayed as expected in a .toString() representation.
The problem is the second JList:
private void AddToSelected_JButtonActionPerformed(java.awt.event.ActionEvent evt) {
Property p = (Property) this.Properties_JList.getSelectedValue();
this.SelectedProperties_JList.setModel(selProperties);
this.selProperties.InsertProperty(p);
this.SelectedProperties_JList.revalidate();
}
Which appears to be displaying only the very first item I attempt to add to it through the above button event, and I have no idea why. I considered moving both .setModel(...) calls right after the form's initComponents() call but if I do that none of the lists gets populated, at all.
Logging messages made it clear that the internal structures are getting populated, but even though they are both respective ListModels for my JLists, one of them isn't working as expected.
A sufficient portion of the code is generated by Netbeans and I have spent hours looking up the API but still have trouble finding out what I'm doing wrong. Any ideas?

Save game to file

I'm working on a primitive RPG, and this class (supposedly) contains all the necessary data:
public class CPU implements Serializable{
private Map<String, Location> locations;
private Map<String, Location> places;
private Map<String, NPC> npcs;
private Game game;
private Player player;
private NPC currentNPC;
public CPU(){
}
(I didn't include the methods, but I think those are irrelevant right now...)
The class "Game" also contains the Player and the CPU as variables, but its constructor isn't the one to actually create them (those are created in the main() method, then added to the classes). This method is the one that's supposed to save the CPU class to a file, so that I can read all the data from it later:
public void SaveGame(String s){
String sav = s;
sav.concat(".dat");
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(sav));
oos.writeObject(cpu);
oos.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
And this is the method to load it from the file:
public void Load(String s){
if(s.contains(".dat")){
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(s));
cpu = (CPU)ois.readObject();
ois.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
My question is basically: will this work? Am I able to simply serialize the CPU class and save it to a file, then read it back and be able to recover all the data from it (i.e the Player data)?
If I remember correctly, in Java "=" doesn't mean that the object on the right side will be copied, so my other problem is: when the method "Load" finishes, will the "cpu" (variable of the "Game"-class) still contain the CPU that I loaded from the file, and will I be able to read data from it?
Actually, it will work only if the original file name that you pass to the SaveGame() method contains ".dat".
Indeed, the reading method checks that condition, and the SaveGame() method (which should be named saveGame() to respect the Java naming conventions) doesn't append .dat to the file name as you think. Indeed, Strings are immutable, and the concat() method returns a new String, but doesn't modify the String it's called on. The code should be
String sav = s.concat(".dat");
You should also stop ignoring exceptions like you're doing, and you should always close the streams in a finally block. If you're under Java 7, use the try-with-resources construct.
If your program has permissions to write files, and all of the field classes (NPC, Game, Player. Location) are serializable as well, then it will work.
The cpu field of the Game class will contain the CPU loaded from the file, if no exception is thrown when reading the object.

Categories

Resources