How can I save values (from textfields, textareas, radiobuttons, etc.) and settings (position of the stage, fullscreen or normal size, etc.) in a file and load from this file ? I have a solution, but this solution does not seem to be the best solution, because it is very much "code" (if I use many components).
I had a look at this: Reading Properties file in Java
http://www.mkyong.com/java/java-properties-file-examples/
But these examples are very simple:
prop.setProperty("database", "localhost");
prop.setProperty("dbuser", "mkyong");
prop.setProperty("dbpassword", "password");
System.out.println(prop.getProperty("database"));
System.out.println(prop.getProperty("dbuser"));
System.out.println(prop.getProperty("dbpassword"));
But 'System.out.println (prop.getProperty("value"));
' is not really 'loading' for me.
There is not shown how I use it in components like textfiels, radiobuttons, checkboxes and so on.
In my code snippet I use different components (textfield, datepicker, rb, cb etc.). Here's my code snippet:
Saving:
public void speichern (ActionEvent event) throws IOException
{
if (filename == null)
speichernUnter (event);
else
{
Properties prop = new Properties ( );
FileOutputStream fos = null;
try
{
prop.setProperty ("Name", textField.getText ( ) ); // Save a textfield
if (radioButton.isSelected ( ) )
prop.setProperty ("RadioButtonState", "yes"); // Save rb state
if (checkBox.isSelected ( ) )
{
prop.setProperty ("CheckBoxState", "yes"); // Save cb state
} else
prop.setProperty ("CheckBoxState", "no"); // or not
prop.setProperty ("Date", datePicker.getValue ( ).toString ( ) ); //Save date
prop.setProperty ("Text", textArea.getText ( ) ); // Save long text
fos = new FileOutputStream (filename);
// Save settings in file
prop.storeToXML (new FileOutputStream (filename), "Values and settings", "UTF-8");
} catch (IOException ex)
{
ex.printStackTrace ( );
} finally
{
if (fos != null)
fos.close ( );
} }
}
public void speichernUnter (ActionEvent event)
{
init ( );
FileChooser fileChooser = new FileChooser ( );
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter ("PROPERTIES Dateien (*.properties)", "*.properties");
fileChooser.getExtensionFilters ( ).add (extFilter);
//Show save file dialog
File file = fileChooser.showSaveDialog (stage);
if (file != null)
{
try
{
FileWriter fileWriter = new FileWriter (file);
fileWriter.close ( );
filename = file.toString ( );
speichern (event);
} catch (IOException ex)
{
Logger.getLogger (Kontroller.class.getName ( ) ).log (Level.SEVERE, null, ex);
}
}
}
Loading:
public void laden (ActionEvent event) throws IOException
{
if (filename == null)
ladenVon (event);
else
{
Properties prop = new Properties ( );
FileInputStream fis = null;
try
{
fis = new FileInputStream (filename);
// Load Properties from saved XML file
prop.loadFromXML (fis);
textField.setText (prop.getProperty ("Name") ); // load the text
if (prop.getProperty ("RadioButtonState").equals ("yes") ) // load rb state
{
radioButton.setSelected ( );
}
if (checkBox.isSelected ( ) ) // Load cb state
checkBox.setSelected (false);
checkBox.setSelected (true);
}
datePicker.setValue (LocalDate.parse (prop.getProperty ("Date") ) ); // load date
textArea.setText (prop.getProperty ("Text") ); // Load long text
} catch (IOException ex)
{
ex.printStackTrace ( );
} finally
{
if (fis != null)
fis.close ( );
}
}
}
public void ladenVon (ActionEvent event) throws IOException
{
init ( );
FileChooser fileChooser = new FileChooser ( );
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter ("PROPERTIES Dateien (*.properties)", "*.properties");
fileChooser.getExtensionFilters ( ).add (extFilter);
//Show load file dialog
File file = fileChooser.showOpenDialog (stage);
if (file != null)
{
try
{
FileReader fileReader = new FileReader (file);
fileReader.close ( );
filename = file.toString ( );
laden (event);
} catch (IOException ex)
{
Logger.getLogger (Kontroller.class.getName ( ) ).log (Level.SEVERE, null, ex);
}
}
}
Do I really have to do this 'prop.setProperty ("Name", textField.getText ( ) );
' for saving and this 'textField.setText (prop.getProperty ("Name") ); // load the text
' for loading for all components?
Is my solution 'correct'?
It all works the way I want it.
But is there a better and faster solution?
Short of using properties and the Bindings API, your solution seems correct. If you find yourself needing to fetch several specific properties multiple times, consider making a static and publicly accessible member that represents the loaded property value so calls to get the value are as easy as field.setText(Props.NAME_VALUE)
, as an example.
You could also consider a helper class that has exclusive access to your properties file and is responsible for loading and saving it. Classes that need values could query your helper class with the key name, and this also allows you to provide overloaded methods for primitive classes (int, long, double, boolean, etc) so you don't have to repeat code to get the value and parse it and could instead use box.setSelected(Props.getBoolean("box_selected"))
, as an example.
The benefit of a helper class is that it removes redundant boilerplate code and can also catch parsing exceptions and return a default value, for example if the specific property could not be found or its value was invalid, or throw the exceptions and force the caller to handle them.