# zustände speichern und beim erneuten programmstart zustände automatisch laden



## huzein (14. Jun 2009)

hey leute, bin neu hier, in java auch eher ein anfänger und hoffe deshalb dass ihr mir weiterhelfen könnt.

ich schreibe gerade ein programm, eine gui, wo ich meine noten eintragen und den durchschnitt berechnen kann. ich studiere und mach das interessehalber. 

was ich nun tun will ist offensichtlich. ich trage die noten ein, und wenn ich das programm beende mit datei->quit soll sich das textfeld die eingegebene note merken und beim nächsten programmstart das feld mit der note automatisch füllen.

das programm hab ich bisher nur in eine jar umwandeln können.


ich denke mir dass das irgendwie mit

```
getRuntime.addShutdownHook(new Thread() {
            // CODE
            }
     });
```

gehen müsste, habs aber nicht hinbekommen...


die bilder unten veranschaulichen das ganze etwas.
vielleicht noch zur info: entworfen wurde die gui mit netbeans.

hoffe auf baldige antwort.
gruß,
huzein


----------



## Marco13 (14. Jun 2009)

ShutdownHook braucht man da wohl nicht - reicht vermutlich schon, wenn man einen WindowListener an das Hauptfenster hängt (und dafür die Zeile
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
rausnimmt)


----------



## SlaterB (14. Jun 2009)

was bedeutet denn 'nicht hinbekommen'?
wird 
// Code 
nicht ausgeführt (erstmal mit System.out.println testen) oder geht es nur noch um das separate Thema des CSV-Datei schreiben/ lesen?

allgemein ist sowas komisches wie addShutdownHook() eher nicht zu empfehlen, höchstens als Notfall-Datenrettung bei unerwartetet Programmbeendung,

wenn du auf den Menüeintrag reagiert, hast du doch dagegen einen Listener oder eine Action, die normalen Code ausführt,
an der Stelle kannst du ganz gemütlich die Daten sichern,

der Sinn der Bilder zu der Frage ist mir noch ein Rätsel


----------



## Michael... (14. Jun 2009)

am einfachsten ist es wohl Du speicherst die Noten in einer Datei. Vielleicht sogar in einem Properties File.
Dann könnte man es auch mit Serialisierung versuchen.
das mit dem *getRuntime.addShutdownHook(new Thread() {...* würde ich mal ganz schnell vergessen, wie kommt man auf sowas?
Entweder man speichert die Eingaben direkt nach der Eingabe, oder durch aktives Speichern des Anwenders, man kann auch beim Schließen der Anwendung speichern, aber auf jeden Fall ist immer eine Listener im Spiel.


----------



## chr (14. Jun 2009)

Reading and Writing a Properties File (Java Developers Almanac Example)


----------



## huzein (14. Jun 2009)

Michael... hat gesagt.:


> *getRuntime.addShutdownHook(new Thread() {...* würde ich mal ganz schnell vergessen, wie kommt man auf sowas?



naja dachte, da der quelltext ja sozusagen verändert wird, ist es am besten es durch die methode zu machen, denn diese bewirkt ja quasi das ausführen von code nachdem die applikation beendet wurde.


//Code nicht hinbekommen sollte heißen, dass das was ich in 


```
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        //Code
    }
});
```

implementiert hab, nicht ausgeführt wurde, bzw. beim erneuten starten der .jar datei, der alte zustand wieder vorlag.

und nun nochwas prinzipielles: die .jar wird doch permanent ergänzt bzw verändert durch speichern der noten etc. ist es da überhaupt möglich den quellcode zu manipulieren? denn die .jar ist ja nun mal gebildet worden mit den default werten der noten. ansonsten scheint mir das mit der properties file eine möglichkeit zu sein, so kann das programm information von außen holen. muss da dann nochmal mich hinsetzen und schauen wie das alles einzubauen ist in das programm und dann versuchen.

mit nem normalen actionperformed auf das menuitem schließen hat nix gebracht. beim erneuten starten des .jar war dann halt wieder der alte zustand zu sehen.


vielen dank für die vielen antworten!
wenn jmd noch ein tip hat, immer her damit.

liebe grüße,
huzein


----------



## SlaterB (14. Jun 2009)

> nicht ausgeführt wurde, bzw. beim erneuten starten der .jar datei, der alte zustand wieder vorlag.

das sind ja zwei völlig verschiedene Dinge, vermutest du vielleicht das erste nur aufgrund des zweiten Ergebnisses?
(wenn sich nach Neustart nix geändert hat, dann ist wohl nix passiert)

später dann nochmal:
> mit nem normalen actionperformed auf das menuitem schließen hat nix gebracht. beim erneuten starten des .jar war dann halt wieder der alte zustand zu sehen.

die Idee, dass mit der Implementierung eines Speichern-Vorgangs dann auch beim nächsten Programmstart irgendwas automatisch geladen wird, ist völlig verrückt,

jede Aktion, die in einem Programm passiert, muss vollständig von dir progranmiert werden,
du musst beim Systemstart aktiv eine Datei einlesen, deren Inhalt interpretieren und diese Werte einzeln auf deine GUI-Komponenten verteilen,

natürlich kann man sich eine relativ automatische Komponente ausdenken, die generisch die GUI analysiert, alle Werte herausliest und abspeichert und beim Neustart die Daten auf gleiche Weise (beschrieben in der Datei) wieder verteilt,
aber selbst wenn es sowas irgendwo gibt, muss auf jeden Fall irgendwo ein Code-Aufruf stehen
'Tool, tue mal was',
von selber passiert nirgendwo was

--------

> die .jar wird doch permanent ergänzt bzw verändert durch speichern der noten etc. ist es da überhaupt möglich den quellcode zu manipulieren? 

Code wird einmal geschrieben und kompiliert, kann aber jederzeit von dir neu geschrieben/ kompiliert werden,
aut anderem Wege ist eine Manipulation unter normalen Umständen ausgeschlossen,
.class-Dateien ändern sich nicht während der Programmausführung, etwa wenn Daten in einer Tabelle/ Liste gespeichert werden

Daten kannst du in anderen Datei speichern (txt, xml, properties), ob man die einfach mal so in eine jar einfügen kann, weiß ich nicht,
besser wahrscheinlich separat im Dateisystem


----------



## bygones (15. Jun 2009)

chr hat gesagt.:


> Reading and Writing a Properties File (Java Developers Almanac Example)


ich wuerde eher ueber Preferences gehen: Preferences API


----------



## huzein (15. Jun 2009)

SlaterB hat gesagt.:


> > du musst beim Systemstart aktiv eine Datei einlesen, deren Inhalt interpretieren und diese Werte einzeln auf deine GUI-Komponenten verteilen



wie lese ich denn vor dem eigentlichen programmstart eine datei ein? hab die gui ja nun mit netbeans entworfen, da ist das alles nicht immer so ersichtlich.

und welche methoden und klassen benötige ich dafür? ist das mit den properties machbar oder benötige ich doch andere hilfsmittel?


für diesen wäre ich noch sehr dankbar. würde dann mal probieren die daten in eine txt datei zu speichern und beim programmstart die daten abzurufen.



deathbyaclown hat gesagt.:


> ich wuerde eher ueber Preferences gehen: Preferences API



kannst du mir vielleicht mal eine deutsche anleitung dazu geben?^^ brauche anleitungen eher auf deutsch als auf englisch, sonst muss erst das wörterbuch raus.


liebe grüße,
huzein


----------



## SlaterB (15. Jun 2009)

mal 3 Sekunden google liefert schon
Preferences java beispiel - Google-Suche

Java Preferences API - BORG Wiki
Erfahrung mit java.util.prefs.Preferences? - Java @ tutorials.de: Forum, Tutorial, Anleitung, Schulung & Hilfe
Beispiel zum Preferences API unter Windows / Registry Lesen/Schreiben - Java @ tutorials.de: Forum, Tutorial, Anleitung, Schulung & Hilfe


----------



## huzein (15. Jun 2009)

ok hab das soweit hinbekommen, mit preferences, dh in die registry einlesen und information wieder abholen. das problem ist nun dass das aber nicht mehr funktioniert sobald das projekt in eine .jar datei umgewandelt wurde. 


vielleicht da noch eine idee?


liebe grüße,

huzein


----------



## Michael... (16. Jun 2009)

Na dann zeig doch mal Deinen Code.
In möglichst gekürzter, auf's Wesentliche reduzierter und kombilierbarer Form.


----------



## huzein (16. Jun 2009)

also ich hab gemerkt dass es funktioniert wenn ich das programm mit eclipse compiliere und eine jar erstelle, aber nicht wenn ich es mit netbeans compiliere und die jar erstelle.

hab in eclipse ein kleines programm geschrieben und getestet.

ich versuch das mal selbst, und wenn ich dann echt nicht weiterkomm dann schreib ich nochmal und setz den code hier rein, danke.

lg


----------



## HannsW (18. Jun 2009)

huzein hat gesagt.:


> also ich hab gemerkt dass es funktioniert wenn ich das programm mit eclipse compiliere und eine jar erstelle, aber nicht wenn ich es mit netbeans compiliere und die jar erstelle.



Mir scheint, daß Du hier verschiedene Dinge versuchst zu klären, un Dir nicht bewusst ist, *daß* verschiedene sind.

ad 1) EIn Programm schreibt man z.b, um Daten zu *erfassen, bearbeiten, speichern *. Die Daten sind- solange das Porgramm aktiv ist, vom Programm / Betriebssystem verwaltet im flüchtigen Speicher: NICHT im Programm.
Daher ist völlig natürlich, daß beim Neustart des Programmes - selbst wenn parallel eine gleich Instance läuft- Die Daten so dargestellt, wie Du sie im Prgramm-Code initialisert hast.

ad 2) wenn Du mehrere Werte  erfassen willst - z.b stündlich die Temperatur, so muss DU im Programm dafür sorgen, daß entsprechend viel SPeicherplätze im Programm reservierst, oder sie in der Reihenfolge, in der sie kommen auf einem Datenträger  speicherst. - Willst du diese alten Werte beim Neustart zur Verfügung haben, musst Du sie von Deinem Progamm einlesen lassen.

ad 3) WEnn Dein Prgramm außerhalb einer IDE läufen soll, müssen bestimmte runtime-Paameter gesetzt sind.

Ich schlage vor, DU kümmerst DIch ersteinmal um das reine Erfassen Deiner Daten, und kannst ja schon wenn Die Werte iengelesen sind eine function

```
boolean schreibeDaten (String einWert){
   System.out.println( einWert);   // wird später durchs richtige Schreiben ersetzt
   return true;// liefert später den richtigen Rückgabewert
}
```

Ich hoffe, Dir helfen zu können 
Hanns


----------



## HannsW (19. Jun 2009)

huzein hat gesagt.:


> was ich nun tun will ist offensichtlich. ich trage die noten ein, und wenn ich das programm beende mit datei->quit soll sich das textfeld die eingegebene note merken und beim nächsten programmstart das feld mit der note automatisch füllen.



Das finde ich recht umständlich.

Der normale weg wäre für mich :

Prgramm starten.
eventuelle vorhanden noten anzeigen ( könnte auch ein extra menupunkt sein)
neue Noten erfassen, und nach sicherheitsabfrage ; speichern.
Menupunkt "Ende" beendet programm.

SO könntest Du Dein Programm ewig laufen haben.

Noch etwas:
Im vorigen Post habe ich die Noten als String-Var gesehen.
Zum weiteren berechnen ( Durchschnitt etc ) brauchst Du natürlich Zahlen.

Aber diese Probleme klären wir später.
wie weit läuft es?
Hanns:applaus:


----------



## huzein (20. Jun 2009)

hi, danke für die anmerkungen!

ja naja ich erfasse daten, nämlich die noten. beim erfassen öffnet sich ein neues fenster ich welchem sich unter anderem das formatierte textfeld noten befindet. dort trage ich sie ein. und bei klicken auf button ok, wird ein key in die registry eingetragen mit dem wert der note. im konstruktor des hauptklasse wird auf die angelegten keys zugegriffen und die werte werden eingelesen. also das funktioniert schon soweit ganz gut. nur ging das nicht mit netbeans, sondern nur nach exportieren einer jar mit eclipse.

das mit dem durchschnitt ist richtig, dass sie als string werte gespeichert werden. natürliche zahlen nicht, aber reelle zahlen, oder hier double sollten sie schon sein beim berechnen des durchschnitts, aber das lässt sich sicherlich noch irgendwie konvertieren.

ich kann ja mal den kompletten quellcode hochladen. oder am besten die klassen. sind auch nur zwei bisher.versuche halt bevor alles komplett wird, erst die funktionalitäten zu implementieren dann kann der rest nach und nach entstehen..


lg
huzein


----------



## huzein (4. Aug 2009)

tach leute, hab nun folgendes problem: ich habe ein JFormattedTextField welches  nur double Zahlen mit maximal einer Nachkommastelle akzeptiert:

```
public class mainwindow extends JFrame implements ActionListener{
private NumberFormat nfNote;
private static JFormattedTextField tf1[] = {noteAna1, noteAna2, noteAna3,...};
...
nfNote = NumberFormat.getInstance();
nfNote.setMaximumFractionDigits(1);
nfNote.setMinimumFractionDigits(1);
...
}

public void erzeugeButtonsUndFelder(String[] str, JPanel jp, JLabel[] m, JFormattedTextField[] u, 
			JFormattedTextField[] v, JButton[] bs, JButton[] bd){
...
 u[i] = new JFormattedTextField(nfNote);
...
}
```

jetzt will ich den durchschnitt berechnen und muss die strings, also die inhalte der textfelder, in double umwandeln.
mit 

```
double d = Double.parseDouble(tf1[i].getText().toString());
```
läuft das nicht. auch nicht mit try-catch. die strings sind anscheinend nicht parsable.
mit *.valueOf()* geht das auch nicht.

habt ihr eine idee, wie ich das hinkriegen könnte?

liebe grüße,
huzein


----------



## Painii (4. Aug 2009)

huzein hat gesagt.:


> habt ihr eine idee, wie ich das hinkriegen könnte?



Erstmal den String einfach mit System.out.println() hinschreiben um zu schauen was überhaupt drin steht (vielleicht ist es ja wirklich keine Zahl).
Wenn das funktioniert dann mal das d danach ausgeben, evtl. wird es ja richtig übernommen und irgendwoanders wird es dann nicht richtig verarbeitet?

Allgemein sagt parseDouble() ja dass es das gleiche liefert wieder valueOf(), also sollte da egal sein was du nimmst.



Und nur so als Anmerkung - Mittlerweile sollte man genug Speicher haben dass Variablennamen länger als 2 Buchstaben sein können.


```
JFormattedTextField tf1[] = {noteAna1, noteAna2, noteAna3,...}
JFormattedTextField noten[] = {noteAna1, noteAna2...}
//Wo sieht man eher was in dem Feld gespeichert wird?
```


----------



## huzein (4. Aug 2009)

mit System.out.println() funktioniert das. die textfeldinhalte werden ausgegeben, sowohl durch .getText() alsauch mit .getText().toString()  . das versuchte in ein double umgewandelte wird nicht ausgegeben, es wird eine NumberFormatException geworfen:


```
try{
double d = Double.parseDouble(tf1[i].getText());
System.out.println(d);
}
catch(NumberFormatException e){}
```

wenns hilft dann kann ich einfach mal den quelltext hochladen, aber ist bisschen viel.
oder vielleicht noch ne idee?


----------



## Murray (4. Aug 2009)

huzein hat gesagt.:


> mit System.out.println() funktioniert das. die textfeldinhalte werden ausgegeben


Wie sehen die Strings denn aus? Ist der Dezimaltrenner ein Punkt oder ein Komma? Gibt es evtl. Leerzeichen vor oder hinter der eigentlichen Zahl?


----------



## huzein (4. Aug 2009)

der dezimaltrenner ist ein komma. es gibt keine leerzeichen vor oder hinter der zahl. die strings werden per preferences in die registry geschrieben und von dort auch wieder gelesen und in die textfelder eingetragen.


```
private String h;
private Preferences prefs = Preferences.systemRoot();
...
public void speichereDaten(JFormattedTextField tf[], String t[], int i)
{
	h = tf[i].getText().toString();
	prefs.put(t[i], h);
	try {
             prefs.flush();
         } 
        catch (BackingStoreException e1) {
             e1.printStackTrace();
         }
}
	
public void ladeDaten(JFormattedTextField[] jft, String[] s)
{
	for(int i=0 ; i<jft.length ; i++)
	jft[i].setText(prefs.get(s[i], h));
}
```

alternativ könnte man die string-werte in eine datei schreiben. vielleicht könntet ihr mir dann sagen, wie man die zeilenweise eingelesenen strings aus der datei in double umwandeln kann, also ungefähr so:

```
BufferedReader br = new BufferedReader(new FileReader(filename));
String s = br.readLine().toString();
double d = Double.parseDouble(s);
```
geht aber auf diese weise auch nicht..

also mit trennzeichen . klappt es. will aber wenns geht mit komma machen.
mit 

```
NumberFormat nfNote = DecimalFormat.getInstance(Locale.GERMANY)
```

gehts trotzdem nicht. dann hat man ja das komma als trennzeichen, aber führt dazu dass der string nicht in double umgewandelt werden kann.


----------



## huzein (4. Aug 2009)

ok habs geschafft, geht mit 

```
double[] notenGemeinsamerTeil = new double[tf1.length];
double[] credGemeinsamerTeil = new double[tf2.length];
...
for(int i=0 ; i<tf1.length ; i++){
	try{
	        if(tf1[i].getText().isEmpty()==false){
                        /*nfNote = DecimalFormat.getInstance(Locale.GERMANY);
		                  nfNote.setMaximumFractionDigits(1);
		                  nfNote.setMinimumFractionDigits(1);
	                      nfCrd = NumberFormat.getIntegerInstance();*/
		        notenGemeinsamerTeil[i] = nfNote.parse(tf1[i].getText()).doubleValue();
                credGemeinsamerTeil[i] = nfCrd.parse(tf2[i].getText()).doubleValue();
		        ...
	        }
	}
	catch(ParseException e){}
}
```


----------



## HannsW (4. Aug 2009)

huzein hat gesagt.:


> ```
> if(tf1[i].getText().isEmpty()==false){
> ```


Das schreibt man so nicht!

```
if( ! tf1[i].getText().isEmpty() ) {
```
Das "!" ist ein not

Oder DU schreibst, um es beim Lesen deutlicher zu machen

```
if( tf1[i].getText().isEmpty() ) {
     // leerer Text: nichts machen 
     ;
} else {
  //hierher Dein code für nicht-leeren Text
}
```

( nur zum Lernen ) 
Gruß Hanns


----------



## huzein (4. Aug 2009)

ja stimmt, hast recht. auf saubere programmierung sollte man schon achten.
danke für den hinweis.

gruß


----------



## huzein (11. Aug 2009)

leutz noch ein problemchen hier.. andere foren und dieses konnten mir nicht helfen, stand zwar einiges drin, aber ging iwie alles nicht. also programm steht soweit, und will es jetzt in eine jar umwandeln. bekanntes problem: bilder werden nicht angezeigt. kurzer auszug:


```
protected static Icon saveData = new ImageIcon("saveData.png");
protected static Icon dela = new ImageIcon("deleteActivated.png");
```

aufbau ist:
Semesternoten -> src -> startup -> klassen

die .png dateien sind auf der ebene von src.


jetzt kommen bestimmt die ersten ideen mit ClassLoader() und getRessource() usw. ging aber nicht, können wir aber gerne nochmal durchkauen. die fehler waren zu meist nullpointer. hab ca 10 klassen und in den meisten werden die benötigt, deshalb protected static.

hoffe ihr könnt mir da auch nochmal weiterhelfen...


gruß
- huzein -


----------



## diggaa1984 (11. Aug 2009)

huzein hat gesagt.:


> jetzt kommen bestimmt die ersten ideen mit ClassLoader() und getRessource() usw. ging aber nicht, können wir aber gerne nochmal durchkauen.



na dann komm ich dir mal damit, weil bei mir klappts, ich zeig dir alles was ich dazu brauch: 

Eine Action welche ein Bild verwendet

```
package tleditor.gui.editor.action;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;

import tleditor.gui.editor.EditorController;


public class SaveFileAction extends AbstractAction {

	private static final long serialVersionUID = 4124908437130866620L;
	
	/**  */
	private EditorController controller;
	
	
	
	public SaveFileAction(EditorController controller) {
		super("Save File");

		Icon icon = new ImageIcon(getClass().getResource("/resources/savefile.png"));
		super.putValue(Action.SMALL_ICON,icon);
		
		this.controller = controller;
	}//constructor
	
	@Override
	public void actionPerformed(ActionEvent e) {
		controller.saveFile(false);
	}//actionPerformed
}//SaveFormulaFileAction
```

Projektstruktur:

Formleditor
src
resources
sämtliche bilder


tleditor
sämtliche packages für java-datein





klappt wunderbar in eclipse und im jar

*EDIT: kannst mal deine Jar aufmachen (is nur ne zip-datei) und schaun ob die Bilder da drin sind!?*


----------



## huzein (11. Aug 2009)

ah nun klappt es tatsächlich. nun klappt es nicht bei eclipse sondern als jar, naja halt wieder der nullpointer zur komplilierzeit. aber danke für deine hilfe!


----------

