Einleitung
Ich trenne für meine Projekte mit grafischer Oberfläche gerne die logischen Teile von denen, die sich um die GUI kümmern.
Dabei entspricht meine Logik wohl dem Controller aus dem MVC-Pattern und stellt damit die Verbindung zwischen den Daten (dem Modell) und der View dar. Er enthält im Normalfall die Daten (die in eigenen Klassen liegen) und eine Verbindung zur Gui.
Die Gui (entspricht der View aus dem MVC-Pattern) bekommt wiederum die Logik “injiziert” (sprich im Konstruktor übergeben), um in ActionListern von Buttons oder ähnlichem die inhaltliche Arbeit an die Logik zu übergeben.
Paketstruktur der Beispiele
Die Struktur der Beispiele in meinem extra für dieses Beispiel erstellte Projekt (was auch die kurzen Paketnamen erklären mag) sieht wie folgt aus:
[ul]
[li] complex[/li] [LIST]
[li] logic[/li] [li] ui[/li] [/ul]
[li] data[/li] [li] simple[/li] [ul]
[li] logic[/li] [li] ui[/li] [/ul]
[li] start[/li][/LIST]
Daten für die Beispiele
Als Daten (entspricht dem Model im MVC-Pattern) verwende ich in den Beispielen eine Person mit den folgenden exemplarischen Daten:
[ul]
[li] Vorname[/li] [li] Nachname[/li] [li] Geburtstag[/li] [li] Straße[/li] [li] Postleitzahl[/li] [li] Ort[/li] [li] Land[/li][/ul]
Die Klasse data.Person
enthält neben dem Konstruktor die Getter und einige Hilfsmethoden, weil ich unveränderliche Objekte mag.
[ot]Dinge wie equals()
und hashCode()
, die diese Klassen normalerweise haben, lasse ich hier weg, weil sie in den Beispielen nicht gebraucht werden.[/ot]
So sieht sie aus:
public class Person {
private final String forename;
private final String surname;
private final String birthday;
private final String street;
private final String postalCode;
private final String town;
private final String country;
public Person(String forename, String surname, String birthday,
String street, String postalCode, String town, String country) {
this.forename = forename;
this.surname = surname;
this.birthday = birthday;
this.street = street;
this.postalCode = postalCode;
this.town = town;
this.country = country;
}
public String getForename() {
return forename;
}
public String getSurname() {
return surname;
}
public String getBirthday() {
return birthday;
}
public String getStreet() {
return street;
}
public String getPostalCode() {
return postalCode;
}
public String getTown() {
return town;
}
public String getCountry() {
return country;
}
@Override
public String toString() {
return "Person [forename=" + forename + ", surname=" + surname
+ ", birthday=" + birthday + ", street=" + street
+ ", postalCode=" + postalCode + ", town=" + town
+ ", country=" + country + "]";
}
public static Person createWithNewForename(Person person, String forename) {
return new Person(forename, person.getSurname(), person.getBirthday(),
person.getStreet(), person.getPostalCode(), person.getTown(),
person.getCountry());
}
public static Person createWithNewSurname(Person person, String surname) {
return new Person(person.getForename(), surname, person.getBirthday(),
person.getStreet(), person.getPostalCode(), person.getTown(),
person.getCountry());
}
public static Person createWithNewBirthday(Person person, String birthday) {
return new Person(person.getForename(), person.getSurname(), birthday,
person.getStreet(), person.getPostalCode(), person.getTown(),
person.getCountry());
}
public static Person createWithNewStreet(Person person, String street) {
return new Person(person.getForename(), person.getSurname(),
person.getBirthday(), street, person.getPostalCode(),
person.getTown(), person.getCountry());
}
public static Person createWithNewPostalCode(Person person,
String postalCode) {
return new Person(person.getForename(), person.getSurname(),
person.getBirthday(), person.getStreet(), postalCode,
person.getTown(), person.getCountry());
}
public static Person createWithNewTown(Person person, String town) {
return new Person(person.getForename(), person.getSurname(),
person.getBirthday(), person.getStreet(),
person.getPostalCode(), town, person.getCountry());
}
public static Person createWithNewCountry(Person person, String country) {
return new Person(person.getForename(), person.getSurname(),
person.getBirthday(), person.getStreet(),
person.getPostalCode(), person.getTown(), country);
}
}```
Einfaches Beispiel
Das einfache Beispiel besteht aus einer Logik- und einer Guiklasse sowie einer Klasse, die das ganze startet. Dem Beispielcharakter geschuldet erfolgen die Ausgaben rundherum schlicht auf die Standardausgabe.
Start des einfachen Beispiels
Den Startpunkt des einfachen Beispielprogramms bildet die Klasse `start.SimpleLogicAndGuiExample`:
```package start;
import data.Person;
import simple.logic.SimpleLogic;
public class SimpleLogicAndGuiExample {
public static void main(String[] args) {
Person person = new Person("Max", "Mustermann", "01.01.1990",
"Musterstraße 123", "12345", "Musterhausen", "Deutschland");
System.out.println("Zu Beginn:
" + person);
SimpleLogic logic = new SimpleLogic(person);
logic.start();
}
}```
Logik des einfachen Beispiels
Die Logik des einfachen Beispielprogramms bildet die Klasse `simple.logic.SimpleLogic`:
```package simple.logic;
import data.Person;
import simple.ui.SimpleGui;
public class SimpleLogic {
private final SimpleGui gui;
private Person person;
public SimpleLogic(final Person person) {
this.person = person;
gui = new SimpleGui(this);
}
public void start() {
gui.show();
}
public String getForename() {
return person.getForename();
}
public String getSurname() {
return person.getSurname();
}
public String getBirthday() {
return person.getBirthday();
}
public String getStreet() {
return person.getStreet();
}
public String getPostalCode() {
return person.getPostalCode();
}
public String getTown() {
return person.getTown();
}
public String getCountry() {
return person.getCountry();
}
public void setForename(final String forename) {
person = Person.createWithNewForename(person, forename);
}
public void setSurname(final String surname) {
person = Person.createWithNewSurname(person, surname);
}
public void setBirthday(final String birthday) {
person = Person.createWithNewBirthday(person, birthday);
}
public void setStreet(final String street) {
person = Person.createWithNewStreet(person, street);
}
public void setPostalCode(final String postalCode) {
person = Person.createWithNewPostalCode(person, postalCode);
}
public void setTown(final String town) {
person = Person.createWithNewTown(person, town);
}
public void setCountry(final String country) {
person = Person.createWithNewCountry(person, country);
}
public void quitPressed() {
System.out.println("Nach Klick auf Quit:
" + person);
quit();
}
private void quit() {
gui.quit();
}
public void okPressed() {
System.out.println("Nach Klick auf OK:
" + person);
quit();
}
}```
Oberfläche des einfachen Beispiels
Die grafische Oberfläche des einfachen Beispielprogramms bildet die Klasse `simple.ui.SimpleGui`:
```package simple.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import simple.logic.SimpleLogic;
public class SimpleGui {
private static final int LABEL_WIDTH = 100;
private static final int FIELD_WIDTH = 300;
private static final int FIELD_HIGHT = 30;
private final SimpleLogic logic;
private final JFrame frame;
private final JTextField forenameField;
private final JTextField surnameField;
private final JTextField birthdayField;
private final JTextField streetField;
private final JTextField postalCodeField;
private final JTextField townField;
private final JTextField countryField;
public SimpleGui(final SimpleLogic logic) {
this.logic = logic;
setNiceLayoutManager();
frame = new JFrame();
forenameField = new JTextField();
surnameField = new JTextField();
birthdayField = new JTextField();
streetField = new JTextField();
postalCodeField = new JTextField();
townField = new JTextField();
countryField = new JTextField();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createGui();
loadPersonDataIntoFields();
}
});
}
private static void setNiceLayoutManager() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
}
catch (Exception e) {
e.printStackTrace();
}
}
private void createGui() {
frame.setTitle("Einfaches Beispiel für Logik und Gui");
frame.setLayout(new BorderLayout());
frame.add(createAllButton(), BorderLayout.SOUTH);
frame.add(createDataPart(), BorderLayout.CENTER);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private Component createAllButton() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(createQuitButton(), BorderLayout.WEST);
panel.add(createGoodButtons(), BorderLayout.EAST);
return panel;
}
private Component createGoodButtons() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(createApplyButton(), BorderLayout.WEST);
panel.add(createOkButton(), BorderLayout.EAST);
return panel;
}
private Component createApplyButton() {
JButton applyButton = new JButton("Apply");
applyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changePersonData();
}
});
return applyButton;
}
private Component createOkButton() {
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changePersonData();
logic.okPressed();
}
});
return okButton;
}
private void changePersonData() {
logic.setForename(forenameField.getText());
logic.setSurname(surnameField.getText());
logic.setBirthday(birthdayField.getText());
logic.setStreet(streetField.getText());
logic.setPostalCode(postalCodeField.getText());
logic.setTown(townField.getText());
logic.setCountry(countryField.getText());
}
private Component createQuitButton() {
JButton quitButton = new JButton("Quit");
quitButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
logic.quitPressed();
}
});
return quitButton;
}
private Component createDataPart() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(createDataButtons(), BorderLayout.EAST);
panel.add(createDataArea(), BorderLayout.CENTER);
return panel;
}
private Component createDataArea() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1, 5, 5));
panel.setBorder(BorderFactory.createTitledBorder(""));
panel.add(createFieldPanel("Nachname", forenameField));
panel.add(createFieldPanel("Vorname", surnameField));
panel.add(createFieldPanel("Geburtsdatum", birthdayField));
panel.add(createFieldPanel("Straße", streetField));
panel.add(createFieldPanel("Postleitzahl", postalCodeField));
panel.add(createFieldPanel("Ort", townField));
panel.add(createFieldPanel("Land", countryField));
return panel;
}
private Component createFieldPanel(String labelText, JTextField field) {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JLabel label = new JLabel(labelText + ":");
label.setPreferredSize(new Dimension(LABEL_WIDTH, FIELD_HIGHT));
field.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HIGHT));
panel.add(label, BorderLayout.WEST);
panel.add(field, BorderLayout.CENTER);
return panel;
}
private Component createDataButtons() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder(""));
JPanel subpanel = new JPanel();
subpanel.setLayout(new BorderLayout());
subpanel.add(createClearAllButton(), BorderLayout.NORTH);
subpanel.add(createReloadButton(), BorderLayout.SOUTH);
panel.add(subpanel, BorderLayout.NORTH);
return panel;
}
private Component createClearAllButton() {
JButton clearAllButton = new JButton("clear");
clearAllButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
forenameField.setText("");
surnameField.setText("");
birthdayField.setText("");
streetField.setText("");
postalCodeField.setText("");
townField.setText("");
countryField.setText("");
}
});
return clearAllButton;
}
private Component createReloadButton() {
JButton reloadButton = new JButton("reload");
reloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loadPersonDataIntoFields();
}
});
return reloadButton;
}
private void loadPersonDataIntoFields() {
forenameField.setText(logic.getForename());
surnameField.setText(logic.getSurname());
birthdayField.setText(logic.getBirthday());
streetField.setText(logic.getStreet());
postalCodeField.setText(logic.getPostalCode());
townField.setText(logic.getTown());
countryField.setText(logic.getCountry());
}
public void quit() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(false);
frame.dispose();
}
});
}
public void show() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(true);
}
});
}
}```