Projekt

Projekt „Java Anwendung markdown2flashcards“ Teil 2 – Grafische Oberfläche mit JavaFX bauen

image_print

erweiterte pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.linformatik</groupId>
    <artifactId>markdown2flashcards</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>markdown2flashcards</name>
    <url>http://linformatik.de</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--GUI für Karteikasten -->
        <!-- JavaFX Dependencies -->
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>19</version>
    </dependency>

    </dependencies>

    <build>
        <plugins>
            <!-- Maven Compiler Plugin für Java Version 21 -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>

  <!-- JFX Plugin für GUI-->
        <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>0.0.5</version>
              <configuration>
                <mainClass>de.linformatik.App</mainClass> <!-- Die Klasse mit der main-Methode -->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
          
            <!-- JAR Plugin für Manifest -->
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- Hauptklasse im Manifest definieren -->
                            <mainClass>de.linformatik.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <!-- Maven Clean Plugin für das Bereinigen des Projekts -->
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>

            <!-- Maven Resources Plugin für das Kopieren von Ressourcen -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>

            <!-- Maven Surefire Plugin für Tests -->
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
            </plugin>

            <!-- Maven Install Plugin für das Installieren der Artefakte -->
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>

            <!-- Maven Deploy Plugin für das Bereitstellen der Artefakte -->
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>

            <!-- Maven Site Plugin für die Erstellung von Sites und Berichten -->
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>

            <!-- Maven Project Info Reports Plugin -->
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>

        </plugins>
    </build>
</project>

Erweiterte App.java


package de.linformatik;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

public class App extends Application {

    private int currentCardIndex = 0;
    private List<Flashcard> flashcards = new ArrayList<>();
    private Map<String, int[]> questionStatistics = new HashMap<>(); // Speichert richtige und falsche Antworten pro Frage
    private Scene flashcardScene;  // Speichern der Flashcard-Szene

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        // Flashcards laden
        String flashcardsPath = loadFlashcardsPathFromConfig();
        if (flashcardsPath != null) {
            flashcards = loadFlashcards(flashcardsPath);
        } else {
            System.out.println("Kein Flashcards-Pfad gefunden.");
        }

        // Textfelder für Frage und Antwort
        Text questionText = new Text();
        Text answerText = new Text();

        // Antwort anfangs unsichtbar
        answerText.setVisible(false);

        // Schriftgrößen für Frage, Antwort und Statistik setzen
        questionText.setStyle("-fx-font-size: 18px;");
        answerText.setStyle("-fx-font-size: 16px;");

        // Button zum Weiterblättern der Karten
        Button nextButton = new Button("Nächste Karte");
        nextButton.setStyle("-fx-font-size: 14px;");
        nextButton.setOnAction(event -> showNextCard(questionText, answerText));

        // Button zum Zurückblättern der Karten
        Button prevButton = new Button("Vorherige Karte");
        prevButton.setStyle("-fx-font-size: 14px;");
        prevButton.setOnAction(event -> showPreviousCard(questionText, answerText));

        // Button zum Anzeigen der Antwort
        Button showAnswerButton = new Button("Antwort anzeigen");
        showAnswerButton.setStyle("-fx-font-size: 14px;");
        showAnswerButton.setOnAction(event -> {
            answerText.setVisible(true);  // Antwort sichtbar machen
        });

        // Button für "Habs gewusst"
        Button correctButton = new Button("Habs gewusst");
        correctButton.setStyle("-fx-font-size: 14px;");
        correctButton.setOnAction(event -> markAnswerCorrect(questionText));

        // Button für "Habs nicht gewusst"
        Button incorrectButton = new Button("Habs nicht gewusst");
        incorrectButton.setStyle("-fx-font-size: 14px;");
        incorrectButton.setOnAction(event -> markAnswerIncorrect(questionText));

        // Buttons nebeneinander anordnen (mit HBox)
        HBox answerButtons = new HBox(10, correctButton, incorrectButton);
        answerButtons.setStyle("-fx-alignment: center;");

        // Buttons für Navigieren und Statistik nebeneinander anordnen
        HBox navButtons = new HBox(10, prevButton, nextButton, showAnswerButton);
        navButtons.setStyle("-fx-alignment: center;");

        // Button für Statistik anzeigen
        Button statsButton = new Button("Statistik anzeigen");
        statsButton.setStyle("-fx-font-size: 14px;");
        statsButton.setOnAction(event -> showStatistics(primaryStage));

        // Layout der GUI
        VBox layout = new VBox(10, questionText, navButtons, answerText, answerButtons, statsButton);
        layout.setStyle("-fx-padding: 20;");

        // Anfangswerte der ersten Karte
        updateCard(questionText, answerText);

        // Erstelle und zeige die Szene
        flashcardScene = new Scene(layout, 1400, 1000);  // Größeres Fenster
        primaryStage.setTitle("Flashcards");
        primaryStage.setScene(flashcardScene);
        primaryStage.show();
    }

    // Liest den Pfad der Flashcards aus der config.xml-Datei
    private String loadFlashcardsPathFromConfig() {
        try {
            // XML-Dokument einlesen
            File configFile = new File("config.xml");
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(configFile);

            // Den Tag <flashcardsPath> auslesen
            NodeList nodeList = document.getElementsByTagName("flashcardsPath");
            if (nodeList.getLength() > 0) {
                Node node = nodeList.item(0);
                return node.getTextContent().trim();  // Rückgabe des Pfads
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null; // Falls keine Datei oder Fehler beim Lesen
    }

    // Lädt die Flashcards aus der angegebenen Datei
    private List<Flashcard> loadFlashcards(String filename) {
        List<Flashcard> flashcards = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            String currentQuestion = null;
            StringBuilder currentAnswer = new StringBuilder();  // Antwort kann mehrere Zeilen haben
    
            while ((line = br.readLine()) != null) {
                line = line.trim();  // Entfernt unnötige Leerzeichen am Anfang und Ende der Zeile
    
                // Wenn eine Frage erkannt wird
                if (line.startsWith("## Frage")) {
                    // Falls bereits eine Frage und Antwort existieren, speichern wir sie
                    if (currentQuestion != null && currentAnswer.length() > 0) {
                        flashcards.add(new Flashcard(currentQuestion, currentAnswer.toString()));
                    }
    
                    // Extrahieren der Frage, nachdem "## Frage <Nummer>:" entfernt wurde
                    currentQuestion = line.substring(9).trim();
                    currentAnswer = new StringBuilder(); // Setze Antwort zurück
                }
                // Wenn eine Antwort erkannt wird
                else if (line.startsWith("**Antwort:**")) {
                    // Füge die Antwortzeile zur bestehenden Antwort hinzu
                    currentAnswer.append(line.substring(12).trim());
                    currentAnswer.append("\n");  // Antwort auf neue Zeile setzen
                }
            }
    
            // Letzte Frage und Antwort hinzufügen, wenn vorhanden
            if (currentQuestion != null && currentAnswer.length() > 0) {
                flashcards.add(new Flashcard(currentQuestion, currentAnswer.toString()));
            }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flashcards;
    }

    // Aktualisiert die Anzeige der aktuellen Karte
    private void updateCard(Text questionText, Text answerText) {
        if (flashcards.size() > 0) {
            Flashcard currentCard = flashcards.get(currentCardIndex);
            questionText.setText("Frage: " + currentCard.question);
            answerText.setText("Antwort: " + currentCard.answer);
            answerText.setVisible(false);  // Antwort anfangs unsichtbar
        } else {
            questionText.setText("Keine Flashcards gefunden.");
            answerText.setText("");
        }
    }

    // Zeigt die nächste Flashcard an
    private void showNextCard(Text questionText, Text answerText) {
        if (currentCardIndex < flashcards.size() - 1) {
            currentCardIndex++;
            updateCard(questionText, answerText);
        }
    }

    // Zeigt die vorherige Flashcard an
    private void showPreviousCard(Text questionText, Text answerText) {
        if (currentCardIndex > 0) {
            currentCardIndex--;
            updateCard(questionText, answerText);
        }
    }

    // Markiert eine Antwort als richtig und aktualisiert die Statistik für diese Frage
    private void markAnswerCorrect(Text questionText) {
        Flashcard currentCard = flashcards.get(currentCardIndex);
        String question = currentCard.question;
        questionStatistics.putIfAbsent(question, new int[]{0, 0});  // Wenn die Frage noch nicht existiert, initialisiere sie
        questionStatistics.get(question)[0]++;  // Richtige Antwort erhöhen
    }

    // Markiert eine Antwort als falsch und aktualisiert die Statistik für diese Frage
    private void markAnswerIncorrect(Text questionText) {
        Flashcard currentCard = flashcards.get(currentCardIndex);
        String question = currentCard.question;
        questionStatistics.putIfAbsent(question, new int[]{0, 0});  // Wenn die Frage noch nicht existiert, initialisiere sie
        questionStatistics.get(question)[1]++;  // Falsche Antwort erhöhen
    }

    // Zeigt die Statistik an
    private void showStatistics(Stage primaryStage) {
        VBox statisticsLayout = new VBox(10);
        statisticsLayout.setStyle("-fx-padding: 20;");

        // Durchlaufen der Fragen und deren Statistiken
        for (Map.Entry<String, int[]> entry : questionStatistics.entrySet()) {
            String question = entry.getKey();
            int[] stats = entry.getValue();
            Text statText = new Text(question + " - Richtige: " + stats[0] + ", Falsche: " + stats[1]);
            statisticsLayout.getChildren().add(statText);
        }

        // Button zum Zurückkehren zur Flashcard-Seite
        Button backButton = new Button("Zurück");
        backButton.setOnAction(event -> primaryStage.setScene(flashcardScene));  // Zurück zur Flashcards-Szene
        statisticsLayout.getChildren().add(backButton);

        // Erstelle und zeige die Statistik-Seite
        Scene statsScene = new Scene(statisticsLayout, 1400, 1000);
        primaryStage.setScene(statsScene);
    }
}

Flashcard.java

package de.linformatik;
public class Flashcard {
    String question;
    String answer;

    Flashcard(String question, String answer) {
        this.question = question;
        this.answer = answer;
    }

    void show() {
        System.out.println("Frage: " + this.question);
        System.out.println("Antwort: " + this.answer);
        System.out.println();
    }
}

Konfiguration für den Pfad der Markdown-Datei config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <flashcardsPath>J:\Meine Ablage\develop\markdown2flashcards\src\main\java\de\linformatik\flashcards.md</flashcardsPath>
</config>

markdown2flashcards.bat um die JAR Datei auszuführen

@echo off
echo Starte JavaFX-Anwendung...
mvn javafx:run -X > output.log 2>&1
echo Anwendung beendet.
pause

Markdowndatei mit den Fragen und Antworten

flashcards.md

## Frage: Was ist der Unterschied zwischen Ganzzahl- und Gleitkomma-Arithmetik?
**Antwort:**  Ganzzahl-Arithmetik bezieht sich auf die Berechnungen mit ganzen Zahlen, während Gleitkomma-Arithmetik für reelle Zahlen verwendet wird.

## Frage: Was ist der Modulo-Operator?
**Antwort:** Der Modulo-Operator `%` gibt den Rest einer Division zurück.

## Frage: Was ist der Unterschied zwischen Addition und Multiplikation?
**Antwort:** Addition ist das Hinzufügen von Zahlen, Multiplikation ist die wiederholte Addition.

## Frage: Was ist eine Primzahl?
**Antwort:** Eine Primzahl ist eine natürliche Zahl größer als 1, die nur durch 1 und sich selbst teilbar ist.

## Frage: Was ist eine Potenz in der Mathematik?
**Antwort:** Eine Potenz besteht aus einer Basis und einem Exponenten und beschreibt eine wiederholte Multiplikation der Basis.

## Frage: Was ist die Binärdarstellung einer Zahl?
**Antwort:** Die Binärdarstellung ist die Darstellung einer Zahl im Zahlensystem zur Basis 2, bestehend nur aus 0 und 1.

## Frage: Was ist eine Fakultät?
**Antwort:** Die Fakultät einer Zahl \( n \) (geschrieben als \( n! \)) ist das Produkt aller natürlichen Zahlen von 1 bis \( n \).

## Frage: Was ist der Unterschied zwischen einem Bruch und einer Dezimalzahl?
**Antwort:** Ein Bruch stellt ein Verhältnis zwischen zwei Zahlen dar, während eine Dezimalzahl eine Darstellung mit einer Kommastelle ist.

## Frage: Was ist die Kommutativität von Addition und Multiplikation?
**Antwort:** Kommutativität bedeutet, dass die Reihenfolge der Operanden das Ergebnis nicht verändert (z. B. \( a + b = b + a \) oder \( a \times b = b \times a \)).

## Frage: Was ist der Unterschied zwischen einer linearen und einer exponentiellen Funktion?
**Antwort:** Eine lineare Funktion wächst konstant, während eine exponentielle Funktion exponentiell wächst (z. B. Verdopplung bei jedem Schritt).

## Frage: Was ist die Basis eines Zahlensystems?
**Antwort:** Die Basis eines Zahlensystems gibt an, mit wie vielen Ziffern Zahlen dargestellt werden (z. B. Basis 10 für Dezimalsystem, Basis 2 für Binärsystem).

## Frage: Was ist eine Logarithmusfunktion?
**Antwort:** Die Logarithmusfunktion ist die Umkehrfunktion der Exponentialfunktion und gibt an, zu welchem Exponenten eine Basis potenziert werden muss, um eine Zahl zu erhalten.

## Frage: Was ist der Unterschied zwischen einem Skalar und einem Vektor?
**Antwort:** Ein Skalar ist eine einzelne Zahl (z. B. Temperatur), während ein Vektor eine Größe mit Richtung und Betrag ist (z. B. Geschwindigkeit).

Printscreen der Applikation

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert