# Aktuellen Stand der Datensätze einer Datenbank anzeigen



## bandy (20. Jan 2011)

Guten Abend,

ich soll bei einem Programm welches Datensätze aus einer Datenbank einliest, die Anzahl der Datensätze in der Datenbank und den aktuellen Datensatz in einem Label (ganz unten) anzeigen lassen. Das ganze Ding soll ungefähr so aussehen:



Dies gelingt mir auch zum Teil, leider habe ich ein Problem dies gleich zu begin des Programms, also wenn das Fenster geöffnet, aber noch kein Button zum durchblättern der Datenbank betätigt wurde, anzuzeigen und es sieht so aus:



Und wenn ich einen Datensatz lösche, soll die Änderung auch sofort sichtbar werden, leider geschieht es nicht, hierfür muss ich das Fenster schliessen und wieder öffnen, erst dann werden die Daten aktualiesiert.

Wie kann dieses Problem gelöst werden?:bahnhof:


----------



## XHelp (20. Jan 2011)

Ich musste jeden Satz mehrmals lesen, bis ich den ungefähren Sinn verstanden habe. Hast du ihn überhaupt verstanden?
Und zu der Frage... welche Antwort erwartest du? "In Zeile 142 muss das "null" weg"?


----------



## bandy (20. Jan 2011)

XHelp hat gesagt.:


> Ich musste jeden Satz mehrmals lesen, bis ich den ungefähren Sinn verstanden habe. Hast du ihn überhaupt verstanden?
> Und zu der Frage... welche Antwort erwartest du? "In Zeile 142 muss das "null" weg"?




Hallo XHelp, wo ist Zeile 142 bitte? 
Ich habe den Sinn verstanden!!! Was verstehst Du in meinem Beitrag nicht?

Sieht so aus als ob dein Beitrag zu anderem Thema waere?:bahnhof:


----------



## XHelp (20. Jan 2011)

bandy hat gesagt.:


> Hallo XHelp, wo ist Zeile 142 bitte?


Eben: wo ist die Zeile 142? Du fragst, wie du irgendwas irgendwo irgendwie anders machen kannst. Dazu könntest du ja sinnvoller weise zeigen, wie du es JETZT machst. KSKB wäre sicherlich hilfreich.


> Was verstehst Du in meinem Beitrag nicht?


Ich finde es verwirrend geschrieben.


----------



## bandy (20. Jan 2011)

XHelp hat gesagt.:


> Eben: wo ist die Zeile 142? Du fragst, wie du irgendwas irgendwo irgendwie anders machen kannst. Dazu könntest du ja sinnvoller weise zeigen, wie du es JETZT machst. KSKB wäre sicherlich hilfreich.
> 
> Ich finde es verwirrend geschrieben.



OK, versuche es noch genauer zu machen.

1. Also ich habe ein Programm mit GUI, welches Daten aus einer Datenbank einliesst und dies anzeigt evt. loescht. Die GUI sieht so aus: 



In der Symbolleiste oben sieht man die Symbole, welche fuer das Loeschen, Speichern der Aenderung, und durchblaettern verwendet werden koennen.

1. Erste Symbol von links loescht einen vorhandenen Datensatz komplett.
2. Zweite Symbol von links speichert Aenderungen an einem Datensatz
3. Dritte Symbol von links wechselt zum ersten Datensatz in der Datenbank
4. Vierte Symbol von links blaettert um einen Datensatz nach unten, wenn man z.B. beim fuenften  
    Datensatz ist und man klickt drauf, wird der vierte Datensatz angezeigt
5. Fuenfte Symbol von links blaettert um einen Datensatz nach oben, wenn man z.B. beim fuenften  
    Datensatz ist und man klickt drauf, wird der sechste Datensatz angezeigt
6. Sechste Symbol von links wechselt zum letzten Datensatz in der Datenbank


```
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.sql.Connection;
import java.sql.ResultSet;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

public class BearbeitenEintrag extends JDialog {
	//automatisch über Eclipse erzeugt
	private static final long serialVersionUID = 2674865770208476234L;
	
	//für die Eingabefelder
	private JTextField name, nachname, strasse, plz, ort, telefon;
	//für die Anzeige
	private JLabel nummer;

	//für die Aktionen
	private MeineAktionen loeschenAct, vorAct, zurueckAct, startAct, endeAct, aktualisierenAct;
	
	//für die Verbindung
	private Connection verbindung;
	private ResultSet ergebnisMenge;
	
	//für die Abfrage
	private String sqlAbfrage;
	
	//eine innere Klasse für die Aktionen
	class MeineAktionen extends AbstractAction {
		//automatisch über Eclipse ergänzt
		private static final long serialVersionUID = 8673560298548765044L;

		//der Konstruktor 
		public MeineAktionen(String text, ImageIcon icon, String beschreibung, KeyStroke shortcut, String actionText) {
			//den Konstruktor der übergeordneten Klasse mit dem Text und dem Icon aufrufen
			super(text, icon);
			//die Beschreibung setzen für den Bildschirmtipp
			putValue(SHORT_DESCRIPTION, beschreibung);
			//den Shortcut
			putValue(ACCELERATOR_KEY, shortcut);
			//das ActionCommand
			putValue(ACTION_COMMAND_KEY, actionText);
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("vor"))
				ganzVor();
			if (e.getActionCommand().equals("zurueck"))
				ganzZurueck();
			if (e.getActionCommand().equals("einenvor"))
				einenVor();
			if (e.getActionCommand().equals("einenzurueck"))
				einenZurueck();
			if (e.getActionCommand().equals("loeschen"))
				loeschen();
			if (e.getActionCommand().equals("aktualisieren"))
				aktualisieren();
		}
	}
	
	//die innere Klasse für die Fenster-Ereignisse
	class FensterListener extends WindowAdapter {
		@Override
		public void windowClosing(WindowEvent e) {
			super.windowClosing(e);
			//die Datenbankverbindung trennen
			//ergebnisMenge und verbindung sind Variablen der äußeren Klasse 
			try {
				BearbeitenEintrag.this.ergebnisMenge.close();
				BearbeitenEintrag.this.verbindung.close();
				MiniDBTools.schliessenDB("jdbc:derby:");
			}
			catch(Exception exc) {
				JOptionPane.showMessageDialog(null, "Problem: \n" + exc.toString());
			}
		}
	}
	
	//der Konstruktor der Klasse BearbeitenEintrag
	public BearbeitenEintrag(JFrame parent, boolean modal) {
		super(parent, modal);
		setTitle("Einträge bearbeiten");
		
		//wir nehmen ein Borderlayout
		setLayout(new BorderLayout());
		//die Aktionen erstellen
		loeschenAct = new MeineAktionen("Datensatz löschen", 
				new ImageIcon("icons/Delete24.gif"), 
				"Löscht den aktuellen Datensatz", 
				null,
				"loeschen");
		vorAct = new MeineAktionen("Einen Datensatz weiter", 
				new ImageIcon("icons/Forward24.gif"), 
				"Blättert einen Datensatz weiter", 
				null, 
				"einenvor");
		zurueckAct = new MeineAktionen("Einen Datensatz zurück", 
				new ImageIcon("icons/Back24.gif"), 
				"Blättert einen Datensatz zurück", 
				null, 
				"einenzurueck");
		startAct = new MeineAktionen("Zum ersten Datensatz",
				new ImageIcon("icons/Front24.gif"), 
				"Geht zum ersten Datensatz", 
				null, 
				"vor");
		endeAct = new MeineAktionen("Zum letzten Datensatz", 
				new ImageIcon("icons/End24.gif"), 
				"Geht zum letzten Datensatz", 
				null, 
				"zurueck");
		aktualisierenAct = new MeineAktionen("Änderungen speichern", 
				new ImageIcon("icons/Save24.gif"), 
				"Speichert Änderungen am aktuellen Datensatz", 
				null, 
				"aktualisieren");
		
		//die Symbolleiste oben einfügen
		add(symbolleiste(), BorderLayout.NORTH);

		//die Oberfläche erstellen und einfügen
		add(initGui(), BorderLayout.CENTER);
		
		//zuerst nehmen wir alle Einträge aus der Tabelle adressen
		sqlAbfrage = "SELECT * FROM adressen";
		//diese Abfrage wählt nur alle Müllers aus
		//sqlAbfrage = "SELECT * FROM adressen WHERE nachname = 'Müller'";
		
		//die Datenbankverbindung herstellen
		initDB();
		
		//die Verbindung mit dem Listener des Fensters herstellen
		addWindowListener(new FensterListener());
		
		//packen und anzeigen
		pack();
		setVisible(true);
		//Standard-Operation setzen
		//hier den Dialog ausblenden und löschen
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
	}
	
	//fügt die Felder in ein Panel ein und liefert das Panel zurück
	private JPanel initGui() {
		JPanel tempPanel = new JPanel();
		//im GridLayout mit zwei Spalten
		tempPanel.setLayout(new GridLayout(0,2));
		//für die Nummer (nur Anzeige)
		tempPanel.add(new JLabel("ID-Nummer:"));
		nummer = new JLabel();
		tempPanel.add(nummer);
		//für die anderen Felder
		tempPanel.add(new JLabel("Vorname:"));
		name = new JTextField();
		tempPanel.add(name);
		tempPanel.add(new JLabel("Nachname:"));
		nachname = new JTextField();
		tempPanel.add(nachname);
		tempPanel.add(new JLabel("Strasse:"));
		strasse = new JTextField();
		tempPanel.add(strasse);
		tempPanel.add(new JLabel("PLZ:"));
		plz = new JTextField();
		tempPanel.add(plz);
		tempPanel.add(new JLabel("Ort:"));
		ort = new JTextField();
		tempPanel.add(ort);
		tempPanel.add(new JLabel("Telefon:"));
		telefon = new JTextField();
		tempPanel.add(telefon);
		//zurückgeben
		return tempPanel;
	}
	
	//die Symbolleiste erzeugen und zurückgeben
	private JToolBar symbolleiste() {
		JToolBar leiste = new JToolBar();
		//die Symbole über die Aktionen einbauen
		leiste.add(loeschenAct);
		leiste.add(aktualisierenAct);
		//Abstand einbauen
		leiste.addSeparator();
		leiste.add(startAct);
		leiste.add(zurueckAct);
		leiste.add(vorAct);
		leiste.add(endeAct);
		
		//die komplette Leiste zurückgeben
		return (leiste);
	}
	
	//die Verbindung zur Datenbank herstellen
	private void initDB() {
		try{
			//Verbindung herstellen und Ergebnismenge beschaffen
			verbindung=MiniDBTools.oeffnenDB("org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:adressenDB");
			ergebnisMenge = MiniDBTools.liefereErgebnis(verbindung, sqlAbfrage);
			if (ergebnisMenge.next()) 
				datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}

	//die Methode liest die Daten und schreibt sie in die Felder
	private void datenLesen() {
		try {
			nummer.setText(Integer.toString(ergebnisMenge.getInt(1)));
			name.setText(ergebnisMenge.getString(2));
			nachname.setText(ergebnisMenge.getString(3));
			strasse.setText(ergebnisMenge.getString(4));
			plz.setText(ergebnisMenge.getString(5));
			ort.setText(ergebnisMenge.getString(6));
			telefon.setText(ergebnisMenge.getString(7));
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}

	//die Methode geht zum ersten Datensatz
	private void ganzVor() {
		try {
			//ganz nach vorne gehen
			ergebnisMenge.first();
			datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}

	//die Methode geht zum letzten Datensatz
	private void ganzZurueck() {
		try {
			//ganz nach hinten gehen
			ergebnisMenge.last();
			datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
}

	//die Methode geht einen Datensatz weiter
	private void einenVor() {
		try {
			//gibt es noch einen Datensatz?
			if (ergebnisMenge.next())
				datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}
	
	//die Methode geht einen Datensatz zurück
	private void einenZurueck() {
		try{
			//gibt es noch einen Datensatz davor?
			if (ergebnisMenge.previous()) 
				datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}
	
	//die Methode löscht einen Datensatz
	private void loeschen() {
		try {
			//wir müssen uns merken, wo wir sind
			int position;
			position = ergebnisMenge.getRow();
			//den Eintrag löschen
			ergebnisMenge.deleteRow();
        	//Ergebnismenge schließen
	        ergebnisMenge.close();
	        // und neu öffnen
			ergebnisMenge = MiniDBTools.liefereErgebnis(verbindung, sqlAbfrage);
			
			//und wieder zur "alten" Position gehen
			ergebnisMenge.absolute(position);
			//stehen wir jetzt hinter dem letzten?
			if (ergebnisMenge.isAfterLast())
				//dann zum letzten gehen
				ergebnisMenge.last();
			//die Daten neu lesen
			datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}

	//die Methode aktualisiert einen Eintrag
	private void aktualisieren() {
		try {
			//wir müssen uns merken, wo wir sind
			int position;
			position = ergebnisMenge.getRow();
			
			//die Daten aktualisieren
        	ergebnisMenge.updateString(2, name.getText());
        	ergebnisMenge.updateString(3, nachname.getText());
        	ergebnisMenge.updateString(4, strasse.getText());
        	ergebnisMenge.updateString(5, plz.getText());
        	ergebnisMenge.updateString(6, ort.getText());
        	ergebnisMenge.updateString(7, telefon.getText());   	
        	//den Datensatz aktualisieren
        	ergebnisMenge.updateRow();
        	//Ergebnismenge schließen
	        ergebnisMenge.close();
	        // und neu öffnen
			ergebnisMenge = MiniDBTools.liefereErgebnis(verbindung, sqlAbfrage);
			//und wieder zur "alten" Position gehen
			ergebnisMenge.absolute(position);
			//die Daten neu lesen
			datenLesen();
		}
		catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Problem: \n" + e.toString());
		}
	}
}
```


```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.swing.JOptionPane;

public class MiniDBTools {
	
	//die Methode lädt den Treiber und stellt die Verbindung her
	//zurückgeliefert wird ein Connection-Objekt
	//übergeben werden der Treiber und Argumente für das Öffnen
	public static Connection oeffnenDB(String treiber, String arg) {
		Connection verbindung = null;
		try {
			//den Treiber laden
			Class.forName(treiber).newInstance();
			//die Datenbank ist adressenDB 
			verbindung = DriverManager.getConnection(arg);
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Problem: \n" + e.toString());
		}
		return verbindung;
	}
	
	//die Methode liefert eine Ergebnismenge
	//übergeben wird die Verbindung und der SQL-Ausdruck
	public static ResultSet liefereErgebnis(Connection verbindung, String sqlAnweisung) {
		ResultSet ergebnisMenge = null;
		try {
			Statement state = verbindung.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
			ergebnisMenge = state.executeQuery(sqlAnweisung);
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Problem: \n" + e.toString());
		}
		return ergebnisMenge;
	}
	
	//die Methode fährt das gesamte Datenbanksystem herunter
	//das wird bei der "embedded" Version von Apache Derby ausdrücklich empfohlen
	//übergeben wird das Protokoll
	public static void schliessenDB(String protokoll) {
		//das Herunterfahren löst bei Erfolg eine Exception aus!!!
		boolean erfolg = false;
		try {
			DriverManager.getConnection(protokoll + ";shutdown=true");
		}
		catch (SQLException e) {
			erfolg = true;
		}
		if (erfolg !=true) 
			JOptionPane.showMessageDialog(null, "Das DBMS konnte nicht heruntergefahren werden.");
	}
}
```

So sieht und funktioniert das Programm in der Grundeinstellung.
Dies soll nun erweitert werden und zwar soll ganz unten im Fenster wenn dieses geoeffnet wird, angezeigt werden welcher Datensatz aktuell angezeigt wird und wieviele in der Datenbank vorhanden sind.(Dies gelingt mir nicht!)
Das ganze soll etwa dann so aussehen:


Erweiterung ist ganz unten!!! "Datensatz: 4 von 4" bedeutet dass der vierte Datensatz geoeffnet ist und dass es vier Datensaetze in der Datenbank vorhanden sind.

Wenn man jetzt auf das vierte Symbol von links klickt, soll der dritte Datensatz angezeigt werden und ganz unten im Fenster soll es dann so ausehen "Datensatz: 3 von 4". (Dies ist mir gelungen)

Wenn man aufs erste Symbol von links klickt, soll der aktuell angezeigte Datensatz geloescht werden, das tut es auch und dadurch aendert sich die Gesamtzahl der Datensaetze in der Datenbank und nun soll es gleich unten im Fenster die Aenderung angezeigt werden, nun soll es z.B. folgendes dort stehen:"Datensatz: 3 von 3". Weil ein Datensatz verschwunden(geloescht) ist!!! (Dies gelingt mir nicht)

Ich suche also nach Moeglichkeit den aktuellen Bestand der Datensaetze in der Datenbank sofort anzeigen zu lassen, also wenn Programm gestartet wird und wenn waehrend der Laufzeit etwas geaendert wird, sowie den aktuell angezeigten Datensatz!!!

So besser? :bahnhof:


----------



## frapo (20. Jan 2011)

bandy hat gesagt.:


> Ich habe den Sinn verstanden!!! Was verstehst Du in meinem Beitrag nicht?



Lass Dich nicht verunsichern 

Nur weil an anderer Deinen Beitrag nicht verstanden hat, heißt es nicht das der Beitrag für andere unverständlich ist .. also ganz entspannt! 

Wenn Du immer aktuell (nach jeder Änderung am Datenbestand) wissen möchtest, wie die Anzahl der gesamten Datensätze lautet, verwende vielleicht sowas wie ein: 
	
	
	
	





```
SELECT COUNT(*) FROM TableName;
```
Den zurückgegeben Wert kann man dann durch das Label anzeigen lassen.

Wenn Du dieses SQL-Statement dann in jeder Methode absetzt, die eine Änderung am Datenbestand herbeiführen könnte, solltest Du stets die aktuelle Anzahl der Datensätze haben. 

Grüße
frapo


----------



## bandy (20. Jan 2011)

frapo hat gesagt.:


> Lass Dich nicht verunsichern
> 
> Nur weil an anderer Deinen Beitrag nicht verstanden hat, heißt es nicht das der Beitrag für andere unverständlich ist .. also ganz entspannt!
> 
> ...



 Danke fuer die Unterstuetzung und Aufmunterung.


Naja, ich habe schon so aehnlich wie du beschrieben hast versucht, nicht direkt mit SQL, aber ueber die Methode getRow(), welche mir die Ergebnise von deinem SQL-Quelltext liefert:


```
private ResultSet ergebnisMenge;
ausgabeString=Integer.toString(ergebnisMenge.getRow());
ausgabe.setText(ausgabeString+" von "+ letzterDatensatz);
```

Die funktioniert ja auch bei mir in den Methoden die fuer das Blaettern in der Datenbank zustaendig sind, leider funktioniert es nicht wenn ich einen Datensatz loesche, oder zu begin, wenn das Programm gestartet wird. Ich habe es ueber Konstruktor versucht, er will aber diesen Quelltext dort nicht haben!!!:rtfm:


----------



## henpara (21. Jan 2011)

> int 	getRow()
> Retrieves the current row number.


aus der java API, das heißt du bekommst nicht die "maximale" Anzahl, sondern nur die aktuelle Zeile, in der du dich befindest.

Alternativ könntest du auch bei "löschen" einfach die Anzahl der Datensätze manuell um eins reduzieren, wobei das natürlich sehr unschön programmiert ist.

Ansonsten würd ich es auch mit select count(*) lösen. Das ist universell, passt zu jedem Button und liefert immer die benötigte richtige Zahl.


----------



## Camino (21. Jan 2011)

Oder ein Model mit einer ArrayList, in welcher die Objekte (= Datensätze) gespeichert und immer aktuell gehalten werden. Bei Änderungen (INSERT, UPDATE, DELETE) werden Datenbank, ArrayList und View aktualisiert. Die Gesamtanzahl der Datensätze ist dann die Grösse der ArrayList. Durch die ArrayList kann dann mit den Buttons navigiert werden und der Index des momentanen Datensatzes angezeigt werden. Wenn der Index 0 erreicht hat (= erster Datensatz), dann wir der Zurück-Button deaktiviert, wenn der maximale Index (= letzter Datensatz) erreicht ist, wird der Vorwärts-Button deaktiviert.


----------



## fastjack (21. Jan 2011)

getRow() müsste eigentlich bei 1 anfangen... count(*) liefert Dir die gesamte Anzahl an Datensätzen. 
Sobald ein Button gedrückt wurde, der den Datenbestand ändert, muss sich Deine GUI daraufhin anpassen, also Modell refreshen, neu laden oder ähnliches.


----------

