Java SQL Werte in GUI anzeigen lassen?

1 Antwort

Ein klassisches MVC-Pattern wäre angebracht.

An deine Model-Klasse Person sollten sich andere Objekte (konkret deine GUI-Instanz) anhängen können, um über Änderungen des Objekts benachrichtigt zu werden.

Beispiel:

class Person {
  private final PropertyChangeSupport support = new PropertyChangeSupport(this);

  private String name;

  public void addPropertyChangeListener(PropertyChangeListener listener) {
    support.addPropertyChangeListener(listener);
  }

  public void removePropertyChangeListener(PropertyChangeListener listener) {
    support.removePropertyChangeListener(listener);
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    String oldName = this.name;
    this.name = name;
    support.firePropertyChange("name", oldName, name);
  }
}

Zum einen bekommt die Klasse Methoden, um Beobachter an- (oder wieder ab-)zuhängen. Des Weiteren werden die Setter um einen Aufruf erweitert, der die beobachtenden Objekte über die Änderung benachrichtigt (firePropertyChange).

Deine Gui-Klasse wiederum implementiert das PropertyChangeListener-Interface:

public class Gui implements PropertyChangeListener {
  private JLabel nameLabel;

  @Override
  public void propertyChange(PropertyChangeEvent event) {
    String propertyName = event.getPropertyName();

    switch (propertyName) {
      case "name":
        this.nameLabel.setText(event.getNewValue());
        break;
      // ...
  }

  // ...
}

und beim Anlegen deiner Person-Instanz muss es natürlich eine Registrierung geben.

Beispiel:

Gui gui = new Gui();
Person person = new Person();
person.addPropertyChangeListener(gui);

Im dritten Schritt wird mindestens ein Controller implementiert. Dieser hätte die Aufgabe, auf ein Ereignis/eine Eingabe auf der grafischen Oberfläche zu reagieren und daraufhin das Model zu ändern.

Angenommen, du liest Daten nach einem Buttonklick ein, könnte ein einfacher Fall so aussehen:

class Gui {
  private Person person;

  public Gui() {
    person = new Person();
    person.addPropertyChangeListener(Gui.this);
    
    JFrame frame = new JFrame();
    // ...
    JButton button = new JButton("Set name");
    button.addActionListener(event -> {
      person.setName("John Doe");
    }
  }

  // ...
}

Statt den Controller über einen Lambda-Ausdruck zu implementieren, könntest du natürlich auch eigene Klassen anlegen.

class ClickController implements ActionListener {
  private final Person person;
  
  public ClickController(Person person) {
    this.person = person;
  }

  @Override
  public void actionPerformed(ActionEvent event) {
    person.setName("John Doe");
  }
}

// in Gui:
button.addActionListener(new ClickController(person));

Denke im Übrigen an, deine GUI innerhalb des Dispatch Event Thread laufen zu lassen. Dort, wo du die Instanzen erstellst, kannst du invokeLater einsetzen.

SwingUtilities.invokeLater(() -> {
  Gui gui = new Gui();
  // etc. ...
});

Schwabe1307 
Beitragsersteller
 17.11.2021, 21:26

Vielen lieben Dank für deine Antwort. Aber ich glaube dein Weg ist viel zu kompliziert für mich. Ich habe wahrscheinlich das Problem falsch beschrieben.
Dürfte ich dir privat schreiben um das Problem genauer zu erklären?

regex9  17.11.2021, 21:51
@Schwabe1307

Mein Lösungsweg zeigt, wie man von Anfang an eine klare Programmstruktur für so ein Programm anlegt, mit dem Ausblick darauf, dass die Daten später auch bearbeitet werden sollen (d.h. der Nutzer gibt einen neuen Namen für eine Person ein und ändert somit den Wert in der Datenbank).

Du könntest alles stumpf in eine Klasse packen:

class Gui {
  public Gui() {
    DatabaseHandler handler = new DatabaseHandler();
    Person person = handler.readPersonData();
    
    JFrame frame = new JFrame("");
    // ...
    JLabel nameLabel.setText(person.getName());
    frame.add(nameLabel);
    // ...
  }
}

hättest damit aber nur eine inflexible Lösung.

Dürfte ich dir privat schreiben um das Problem genauer zu erklären?

Erkläre es doch einfach hier. 😉

Schwabe1307 
Beitragsersteller
 17.11.2021, 21:53
@regex9

ich würde es gerne hier erklären aber bekomme diese code felder ned hin

Schwabe1307 
Beitragsersteller
 17.11.2021, 22:08
@regex9
public class Person {
	private String vorname;
	private String nachname;
	private int nummer;

	public Person(String vorname, String nachname, int nummer) {
		super();
		this.vorname = vorname;
		this.nachname = nachname;
		this.nummer= nummer;
	}
	
	public String toString() {
		return "Person vorname=" + vorname + ", nachname=" + nachname + ", nummer=" + nummer;
	}


	public String getVorname() {
		return vorname;
	}


	public void setVorname(String vorname) {
		this.vorname = vorname;
	}


	public String getNachname() {
		return nachname;
	}


	public void setNachname(String nachname) {
		this.nachname = nachname;
	}


	public int getNummer() {
		return nummer;
	}


	public void setNummer(int nummer) {
		this.nummer = nummer;
	}
}
public class Datenbank {


	public static void main(String[] args) {
		Person person;


		try {
			System.out.println("MySQL DB");


			String url = "xxx";
			String dbName = "xxx";
			String driver = "com.mysql.cj.jdbc.Driver";
			String userName = "xxx";
			String password = args[0];


			Connection connection = null;
			ResultSet rs;


			connection = DriverManager.getConnection(url + dbName, userName, password);
			System.out.println("Connected to Database");


			Statement statement = connection.createStatement();

			Class.forName(driver);

			connection.createStatement();
			rs = statement.executeQuery("SELECT Mnr, Vorname, Nachname FROM personen");


			while (rs.next()) {
				int nummer = rs.getInt("Nr");
				String nachname = rs.getString("Nachname");
				String vorname = rs.getString("Vorname");


				person = new Person(vorname, nachname, nummer);	
				
			}
			
			connection.close();
			System.out.println("Disconected from Database");


		} catch (Exception e) {
		}}

Das waren 2 meiner 3 Klassen. Dann kommt nur noch die GUI Anwendung die ist aber erstmal irrelevant. Das Problem was ich habe ist halt dass ich die results von der sql abfrage als werte für die person speichern möchte. Aber ich weiß nicht wie


regex9  17.11.2021, 22:42
@Schwabe1307

Es sieht eigentlich schon fast richtig aus. Du musst nur bedenken, dass dir der SELECT alle Datensätze, also alle Personen aus der Datenbank holt. Demzufolge kannst du eine Liste an Personen erwarten.

List<Person> personen = new ArrayList<>();

while (rs.next()) {
  int nummer = rs.getInt("Nr");
  String nachname = rs.getString("Nachname");
  String vorname = rs.getString("Vorname");

  Person person = new Person(vorname, nachname, nummer);
  personen.add(person);
}

Wenn du nur eine einzige Person haben wolltest, solltest du deinen SQL-Query begrenzen. Indem du bspw. (via WHERE-Klausel) nach einer bestimmten Person suchst:

SELECT Mnr, Vorname, Nachname FROM personen WHERE vorname='Max'

oder die Auswahl begrenzt. Dieser Query würde dir nur den ersten Eintrag liefern.

SELECT Mnr, Vorname, Nachname FROM personen LIMIT 1

Folglich bräuchtest du auch keine Schleife mehr (und ebenso keine Liste).

PS: Ich würde dir raten, keinen Sprachmix (Deutsch-Englisch, wie setVorname) einzuschlagen, sondern dich für nur eine Sprache zu entscheiden. Das (sowie die Wahl aussagekräftigerer Variablennamen, z.B. resultData statt rs) macht dein Programm einfacher lesbar.

PPS.: Den expliziten Aufruf des Basiskonstruktors (super) kannst du dir sparen. Der macht nur Sinn, wenn der Basiskonstruktor tatsächlich noch Argumente erwartet.