Ergebnis Code BOPRO2
Dieser Code stellt eine komplette Anwendung dar, die es ermöglicht, Fahrer und deren Fahrten zu verwalten. Die KilometerVerwaltung-Klasse liest die kilometer.csv-Datei ein und speichert die Daten in einer Map. Die FahrAwayGUI-Klasse stellt die Benutzeroberfläche bereit, in der Fahrer ausgewählt und deren Fahrten angezeigt werden können. Neue Fahrten können über die Eingabefelder und den „Fahrt erfassen“-Button hinzugefügt werden. Der FahrtenUpdater-Thread überwacht die addfahrten.csv-Datei, liest neue Fahrten ein und aktualisiert die Daten der Anwendung. Die GUI wird automatisch aktualisiert, wenn neue Fahrten hinzugefügt werden. Der FahrtenUpdater-Thread wird beim Schließen der Anwendung ordnungsgemäß gestoppt.
// FahrAway Kilometerverwaltung // Version 3.11 // Datum 21.04.2024 // André Reichert-Creutz import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; // Klasse, um Informationen über einen Fahrer zu speichern class Fahrer { private String personalnummer; private String vorname; private String nachname; private List<Fahrt> fahrten; public Fahrer(String personalnummer, String vorname, String nachname) { this.personalnummer = personalnummer; this.vorname = vorname; this.nachname = nachname; this.fahrten = new ArrayList<>(); } // Getter-Methoden für Fahrerinformationen public String getPersonalnummer() { return personalnummer; } public String getVorname() { return vorname; } public String getNachname() { return nachname; } // Methode, um eine Fahrt zum Fahrer hinzuzufügen public void addFahrt(Fahrt fahrt) { fahrten.add(fahrt); fahrten.sort(null); // Sortiere die Fahrten nach Datum } // Getter-Methode für die Liste der Fahrten des Fahrers public List<Fahrt> getFahrten() { return fahrten; } // Überschriebene toString-Methode für die Darstellung eines Fahrers @Override public String toString() { return personalnummer + " - " + vorname + " " + nachname; } } // Klasse, um Informationen über eine Fahrt zu speichern class Fahrt implements Comparable<Fahrt> { private String personalnummer; private LocalDate datum; private String startort; private int kilometer; public Fahrt(String personalnummer, LocalDate datum, String startort, int kilometer) { this.personalnummer = personalnummer; this.datum = datum; this.startort = startort; this.kilometer = kilometer; } // Getter-Methoden für Fahrtinformationen public String getPersonalnummer() { return personalnummer; } public LocalDate getDatum() { return datum; } public String getStartort() { return startort; } public int getKilometer() { return kilometer; } // Vergleichsmethode, um Fahrten nach Datum zu sortieren @Override public int compareTo(Fahrt other) { return this.datum.compareTo(other.datum); } // Überschriebene toString-Methode für die Darstellung einer Fahrt @Override public String toString() { return String.format("%s - %s - %d km", datum.format(DateTimeFormatter.ISO_LOCAL_DATE), startort, kilometer); } } // Klasse zur Verwaltung der Kilometerdaten class KilometerVerwaltung { private static final String CSV_FILE = "kilometer.csv"; private static final String ADD_FAHRTEN_CSV = "addfahrten.csv"; private Map<String, Fahrer> fahrerMap = new HashMap<>(); // Methode zum Einlesen der CSV-Datei public void einlesenCsvDatei() { try (BufferedReader br = new BufferedReader(new FileReader(CSV_FILE))) { String line; while ((line = br.readLine()) != null) { String[] data = line.split(","); if (data[0].equals("Fahrer")) { Fahrer fahrer = new Fahrer(data[1], data[2], data[3]); fahrerMap.put(data[1], fahrer); } else if (data[0].equals("Fahrt")) { LocalDate datum = LocalDate.parse(data[2], DateTimeFormatter.ISO_LOCAL_DATE); Fahrt fahrt = new Fahrt(data[1], datum, data[3], Integer.parseInt(data[4])); Fahrer fahrer = fahrerMap.get(data[1]); if (fahrer != null) { fahrer.addFahrt(fahrt); } } } } catch (IOException e) { e.printStackTrace(); } } // Methode zum Speichern der CSV-Datei public void speichernCsvDatei() { try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(CSV_FILE)))) { out.println("Fahrer,Personalnummer,Vorname,Nachname"); for (Fahrer fahrer : fahrerMap.values()) { out.printf("Fahrer,%s,%s,%s%n", fahrer.getPersonalnummer(), fahrer.getVorname(), fahrer.getNachname()); } out.println("Fahrt,Personalnummer,Datum,Startort,Kilometer"); for (Fahrer fahrer : fahrerMap.values()) { for (Fahrt fahrt : fahrer.getFahrten()) { out.printf("Fahrt,%s,%s,%s,%d%n", fahrt.getPersonalnummer(), fahrt.getDatum().format(DateTimeFormatter.ISO_LOCAL_DATE), fahrt.getStartort(), fahrt.getKilometer()); } } } catch (IOException e) { e.printStackTrace(); } } // Getter-Methode für die Fahrer-Map public Map<String, Fahrer> getFahrerMap() { return fahrerMap; } // Methode zur Überprüfung der Existenz einer Datei public boolean checkFileExistence(String filename) { File file = new File(filename); return file.exists() && file.isFile(); } // Methode zur Überprüfung der Schreibbarkeit einer Datei public boolean checkFileWritable(String filename) { File file = new File(filename); return file.exists() && file.canWrite(); } } // Klasse zur Aktualisierung der Fahrten im Hintergrund class FahrtenUpdater implements Runnable { private KilometerVerwaltung kilometerVerwaltung; public FahrtenUpdater(KilometerVerwaltung kilometerVerwaltung) { this.kilometerVerwaltung = kilometerVerwaltung; } // Methode zum kontinuierlichen Aktualisieren der Fahrten @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { // Überprüfe, ob die CSV-Datei existiert und beschreibbar ist if (kilometerVerwaltung.checkFileExistence(KilometerVerwaltung.ADD_FAHRTEN_CSV) && kilometerVerwaltung.checkFileWritable(KilometerVerwaltung.ADD_FAHRTEN_CSV)) { List<String> fahrtenLines = Files.readAllLines(Paths.get(KilometerVerwaltung.ADD_FAHRTEN_CSV)); for (String line : fahrtenLines) { String[] data = line.split(","); LocalDate datum = LocalDate.parse(data[1], DateTimeFormatter.ISO_LOCAL_DATE); int kilometer = Integer.parseInt(data[3]); if (kilometer < 0) { throw new IllegalArgumentException("Negative Kilometeranzahl"); } Fahrt fahrt = new Fahrt(data[0], datum, data[2], kilometer); Fahrer fahrer = kilometerVerwaltung.getFahrerMap().get(data[0]); if (fahrer != null) { fahrer.addFahrt(fahrt); } else { System.out.println("Fahrer mit Personalnummer " + data[0] + " nicht gefunden."); } } Files.delete(Paths.get(KilometerVerwaltung.ADD_FAHRTEN_CSV)); // Aktualisiere die GUI nach dem Einlesen neuer Fahrten if (FahrAwayGUI.getInstance() != null) { FahrAwayGUI.getInstance().aktualisiereGUI(); } } // Warte eine Minute, bevor der nächste Aktualisierungsschritt erfolgt Thread.sleep(60000); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } // Haupt-GUI-Klasse für die Benutzeroberfläche public class FahrAwayGUI { private JFrame frame; private JComboBox<Fahrer> fahrerComboBox; private JTextArea fahrtenTextArea; private JTextField datumTextField, startortTextField, kilometerTextField; private JButton erfassenButton, beendenButton; private JLabel gesamtKilometerLabel; private KilometerVerwaltung kilometerVerwaltung; private static FahrAwayGUI instance; private Thread fahrtenUpdaterThread; // Konstruktor für die GUI public FahrAwayGUI(KilometerVerwaltung kilometerVerwaltung) { this.kilometerVerwaltung = kilometerVerwaltung; frame = new JFrame("FahrAway Kilometerverwaltung"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); // Initialisiere GUI-Komponenten fahrerComboBox = new JComboBox<>(); fahrtenTextArea = new JTextArea(10, 30); fahrtenTextArea.setEditable(false); datumTextField = new JTextField(10); startortTextField = new JTextField(10); kilometerTextField = new JTextField(10); erfassenButton = new JButton("Fahrt erfassen"); beendenButton = new JButton("Beenden"); gesamtKilometerLabel = new JLabel("Gesamtkilometer: 0"); // Panel für Fahrer-Auswahl und Fahrt-Erfassung JPanel northPanel = new JPanel(); northPanel.add(fahrerComboBox); northPanel.add(erfassenButton); // Panel für die Anzeige der Fahrten JPanel centerPanel = new JPanel(); centerPanel.add(new JScrollPane(fahrtenTextArea)); // Panel für die Eingabe neuer Fahrten und Beenden-Button JPanel southPanel = new JPanel(); southPanel.add(new JLabel("Datum:")); southPanel.add(datumTextField); southPanel.add(new JLabel("Startort:")); southPanel.add(startortTextField); southPanel.add(new JLabel("Kilometer:")); southPanel.add(kilometerTextField); southPanel.add(beendenButton); southPanel.add(gesamtKilometerLabel); // Füge Panels zum Frame hinzu frame.add(northPanel, BorderLayout.NORTH); frame.add(centerPanel, BorderLayout.CENTER); frame.add(southPanel, BorderLayout.SOUTH); // ActionListener für Erfassen-Button und Beenden-Button erfassenButton.addActionListener(e -> erfasseFahrt()); beendenButton.addActionListener(e -> { kilometerVerwaltung.speichernCsvDatei(); // Speichere Daten beim Beenden stoppeFahrtenUpdater(); // Stoppe den Hintergrundthread System.exit(0); // Beende die Anwendung }); // ActionListener für die Auswahl eines Fahrers fahrerComboBox.addActionListener(e -> aktualisiereFahrtenAnzeige()); // Packe und mache den Frame sichtbar frame.pack(); frame.setVisible(true); // Lade verfügbare Fahrer in die ComboBox ladeFahrerInComboBox(); // Setze die Instanz für die GUI instance = this; } // Methode zum Laden der verfügbaren Fahrer in die ComboBox private void ladeFahrerInComboBox() { kilometerVerwaltung.getFahrerMap().values().forEach(fahrerComboBox::addItem); } // Methode zur Aktualisierung der Anzeige der Fahrten private void aktualisiereFahrtenAnzeige() { Fahrer ausgewaehlterFahrer = (Fahrer) fahrerComboBox.getSelectedItem(); if (ausgewaehlterFahrer != null) { fahrtenTextArea.setText(""); // Lösche vorherige Einträge ausgewaehlterFahrer.getFahrten().forEach(fahrt -> fahrtenTextArea.append(fahrt.toString() + "\n")); // Füge neue Einträge hinzu int gesamtKilometer = ausgewaehlterFahrer.getFahrten().stream().mapToInt(Fahrt::getKilometer).sum(); gesamtKilometerLabel.setText("Gesamtkilometer: " + gesamtKilometer); // Aktualisiere Gesamtkilometer-Anzeige } } // Methode zur Erfassung einer neuen Fahrt private void erfasseFahrt() { try { Fahrer ausgewaehlterFahrer = (Fahrer) fahrerComboBox.getSelectedItem(); if (ausgewaehlterFahrer != null) { LocalDate datum = LocalDate.parse(datumTextField.getText(), DateTimeFormatter.ISO_LOCAL_DATE); String startort = startortTextField.getText(); int kilometer = Integer.parseInt(kilometerTextField.getText()); if (kilometer < 0) { throw new IllegalArgumentException("Negative Kilometeranzahl"); } Fahrt neueFahrt = new Fahrt(ausgewaehlterFahrer.getPersonalnummer(), datum, startort, kilometer); ausgewaehlterFahrer.addFahrt(neueFahrt); aktualisiereFahrtenAnzeige(); // Aktualisiere die Anzeige nach Erfassung einer neuen Fahrt } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(frame, "Kilometer müssen eine ganze Zahl sein.", "Fehler", JOptionPane.ERROR_MESSAGE); } catch (Exception ex) { JOptionPane.showMessageDialog(frame, "Fehler bei der Eingabe: " + ex.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE); } } // Methode zur Aktualisierung der GUI-Komponenten aus einem anderen Thread public void aktualisiereGUI() { SwingUtilities.invokeLater(this::aktualisiereFahrtenAnzeige); } // Methode zum Starten des Hintergrundthreads zur Aktualisierung der Fahrten public void starteFahrtenUpdater() { fahrtenUpdaterThread = new Thread(new FahrtenUpdater(kilometerVerwaltung)); fahrtenUpdaterThread.start(); } // Methode zum Stoppen des Hintergrundthreads zur Aktualisierung der Fahrten public void stoppeFahrtenUpdater() { if (fahrtenUpdaterThread != null) { fahrtenUpdaterThread.interrupt(); } } // Hauptmethode zum Starten der Anwendung public static void main(String[] args) { KilometerVerwaltung kilometerVerwaltung = new KilometerVerwaltung(); kilometerVerwaltung.einlesenCsvDatei(); // Lade vorhandene Daten aus der CSV-Datei SwingUtilities.invokeLater(() -> { FahrAwayGUI gui = new FahrAwayGUI(kilometerVerwaltung); gui.starteFahrtenUpdater(); // Starte den Hintergrundthread zur Aktualisierung der Fahrten }); } } // Ende
