**Dies ist eine alte Version des Dokuments!**
Tutorial OOP
Setup
Hausaufgabe
- Downloade und installiere den Editor/ die IDE Virtual Studio Code, kurz VS Code, : https://code.visualstudio.com <br>Es ist sehr empfohlen, bei der Installation die folgenden Optionen anzuwählen: * Aktion „Mit Code öffnen“ dem Dateikontextmenu von Windows-Explorer hinzufügen * Aktion „Mit Code öffnen“ dem Verzeichniskontextmenu von Windows-Explorer hinzufügen * Zu PATH hinzufügen
Auch empfohlen ist die Option: * Code als Editor für unterstützte Dateitypen registrieren
Diese Option macht VS Code zu deinem Standardeditor. Entscheide selbst, ob du dies möchtest. Mein Tipp: Mache es, VS Code ist wirklich toll!
- Erstelle einen Account auf GitHub: https://github.com
- Falls du unter Windows arbeitest: Installiere Git. Lade Git hier herunter und installiere es https://gitforwindows.org/. Bei der Installation wirst du einige Entscheidungen treffen müssen. Wähle die folgendenOption: * „Use Git from Git Bash only“ * „Use the OpenSSL library“ * „Checkout Windows-style, commit Unix-style line endings“ * „Use MinTTY“ * Wähle bei den „Configuring extra options“ alle Optionen an
- Du kannst gerne bereits mit den Schritten beschrieben in In Lektion und in Auftrag nach erster Lektion.
In Lektion {#In_Lektion}
- Erstelle auf GitHub ein neues Repository: * Namen: tutorialoopvoci * private Repo * mit Gitignore-File (Programmiersprache: Python)
Achtung: Bitte achte darauf, alle Vorgaben, was das Benennen von Ordnern, Repositories und Files angeht, zu 100% zu befolgen, inkl. Gross- & Kleinschreibweise
- clone dieses Repo auf deinen Computer.
- Öffne diesen Ordner in VS Code (File / Open Folder)
- Erstelle in VS Code ein File
helloworld.py
mit dem üblichen Inhalt <code python> print(„Hello World!“) </code> - Speichere, füge das File dem Git-Repo hinzu, committe und pushe nach GitHub.
- Vergewissere dich, dass die Änderung auf GitHub angekommen ist.
- Füge anschae als Collaborator dieses Repos hinzu.
Auftrag nach erster Lektion {#Auftrag_nach_erster_Lektion}
Studiere im Tutorial Python Setup die folgenden Kapitel. Die Schritte, die du explizit machen sollst, werden explizit genannt:
- Kapitel 1 (Abstract)
- Kapitel 2 (Terminal)
- Kapitel 3 (System-Installation von Python):
- Nimm eine System-Installation von Python vor.
- Kapitel 4 (Ausführen von Python Programmen):
- Führe ein Python-Programm in der Konsole aus.
- Kapitel 6 (Git und GitHub):
- In der Lektion haben wir ein Repo auf GitHub erstellt und dieses auf den Computer geklont. Nimm an diesem Repo auf deinem Computer Änderungen vor: Ändere das vorhandene File, füge weitere Files hinzu, committe deine Änderungen und pushe diese nach GitHub. Stelle sicher, dass alles funktioniert.
- Kapitel 7 (7 IDE (Integrated Development Environment)
- Kapitel 8 (Visual Studio Code)
- Richte VS Code für das Programmieren mit Python ein.
Dauerauftrag
In diesem Tutorial wirst du mehrere Python-Programme schreiben. Füge diese alle unaufgefordert dem Git-Repository tutorialoopvoci hinzu und pushe alle Änderungen nach GitHub. Hast du den Auftrag, eine gewisse Aufgabe bis Datum X zu erledigen, so wird erwartet, dass bis dann das zugehörige Python-File auf deinem GitHub-Account zu finden ist.
Theorie OOP I (Einführung)
Es gibt verschiedene, fundamental unterschiedliche Stile, wie man Programmieren kann. Diese Programmierstile nennt man auch Programmierparadigmen. Python ist eine Multiparadigmensprache. Das bedeutet, Python zwingt den Programmierer nicht zu einem einzigen Programmierstil, sondern erlaubt, das für die jeweilige Aufgabe am besten geeignete Paradigma zu wählen.
Den Code, den wir bisher geschrieben haben, ordnet man der prozeduralen Programmierung betrieben. Der Code wird von oben nach unten ausgeführt. Dabei durchläuft der Code Schlaufen und es werden Funktionen aufgerufen. Mit dieser Art der Programmierung kann man eigentlich alles umsetzen. Allerdings wird der Code, sobald er eine gewisse Länge und Komplexität aufweisst, sehr unübersichtlich. Der Code beinhaltet dann viele verschiedene Funktionen, die wild durcheinander aufgerufen werden. Das macht es sehr schwwierig, die Übersicht zu behalten. Noch schlimmer ist es, wenn man einen solchen Code, der eine andere Person geschrieben hat, lesen und verstehen möchte. Solchen Code nennt man Spaghetti Code.
Eine Abhilfe hier bietet ein anderes Programmierparadigma, die objektorientierte Programmierung (OOP).
Eine schöne Motivation und Einführung in die objektorientierte Programmierung findest du hier: https://www.youtube.com/watch?v=pTB0EiLXUC8
In diesem Tutorial wirst du ein Konsolenprogramm (also ohne graphische Oberfläche) schreiben, und zwar ein Voci Trainer. Dabei die objektorientierte Programmierung kennenlernen.
Zentral in der OOP sind Klassen. In unserem Programm wollen wir ein Wort z.B. in Englisch anzeigen lassen und der Anwender tippt dann das Wort in einer anderen Sprache, z.B. Deutsch, ein. Wir haben also ganz viele Wortpaare (z.B. One - Eins, Two - Zwei, Three - Drei, …), die gespeichert werden müssen. Jedes Wortpaar ist gleich aufgebaut: Es beinhaltet zwei Attribute und zwar wordL1
und wordL2
(steht für word language 1 und word language 2). Die genauen Inhalte der Attribute sind für jeses Wortpaar unterschiedlich, die Struktur ist aber immer gleich. Man kann sich Klassen also Vorlagen für Objekte vorstellen.
Wir definieren deshalb eine Klasse WordPair
. Wir befolgen die Konvention, dass Klassennamen mit Grossbuchstaben beginnen:
class WordPair: def __init__(self,w1,w2): self.wordL1 = w1 self.wordL2 = w2
Hat man eine Klasse definiert, kann man Instanzen dieser Klasse erzeugen. Diese Instanzen werden Objekte genannt - deshalb der Name objektorientierte Programmierung. Dies macht man wie folgt:
wp1 = WordPair("Hello", "Hallo") wp2 = WordPair("World", "Welt")
Wir erzeugen zwei Wortpaare (wp1
und wp2
).
Beachte, dass die Klasse die __init__
Methode beinhaltet. Diese wird Konstruktor genannt: Sie wird jedesmal (und nur dann) aufgerufen, wenn eine neue Instanz der Klasse erzeugt (oder konstruiert) wird.
Das erste Argument im Konstruktor ist immer self
. Danach kommen, falls vorhanden, die Argumente, die man dem Konstruktor übergeben möchte, um Instanzen zu erzeugen. Wir wollen ja Wortpaare erzeugen, also müssen wir zwei Worte für die Erzeugung einer Instanz angeben (w1
und w2
).
Hat man eine Instanz einer Klasse erzeugt, kann man ganz einfach auf deren Attribute zugreifen:
print(wp1.wordL2)
Output:
Hallo
Wir können jetzt eine Voci-Liste erstellen, die lauter Wortpaare beinhaltet:
Voci = [ WordPair("One", "Eins"), WordPair("Two", "Zwei"), WordPair("Three", "Drei"), WordPair("Four", "Vier"), WordPair("Fife", "Fuenf") ]
Aufgabe 1 (voci_trainer_v01)
Erstelle nun die erste Version deines Voci-Trainers. Erstelle ein leeres Python-File voci_trainer_v01.py
.
- Dein Code soll nun in einer Endlosschlaufe laufen.
- Nun soll per Zufall ein Wortpaar aus der Voci-Liste ausgewählt und das Wort in der einen Sprache angezeigt werden.
- Der Benutzer soll nun aufgefordert werden, die Übersetzung einzutippen.
- Der Code überprüft, ob die Übersetzung stimmt oder nicht. Es wird eine Rückmeldung angegeben. Der Benutzer wird aufgefordert, Enter zu drücken, um fortzufahren.
- Ist die Übersetzung falsch, muss es der Benutzer weiter probieren, bis er es schafft. Ist die Übersetzung richtig, so wird per Zufall das nächste Wortpaar ausgewählt. Für jede neue Eingabe (egal ob zuvor richtig oder falsch), soll die Konsole geleert werden.
Tipps zu den Schritten oben: 1. Die Endlosschlaufe erziehlst du mit:
while True: # MEIN CODE
2. Benutze dazu das random
Modul. Füge in der ersten Zeile deines Codes die folgende Zeile import random
ein.
Um aus einer Liste L
ein zufälliges Element auszuwählen, tippe random.choice(L)
.
3. Text in Konsole eintippen inp = input("Text, der in Konsole angezeigt wird")
. inp
(oder welchen Variablennamen man auch immer wählt) ist dann ein String, der im Code verwendet werden kann.
4. Kein Tipp notwendig
5. Die Konsole leeren kannst du mit os.system('cls||clear')
. Dazu musst du am Anfang das deines Code das os
Modul importieren: import os
.
Für den Code bisher würde es sich auch anbieten, ein dictionary anstelle einer Klasse für die Wortpaare zu erstellen. Ein dictionary ist eine Sammlung von Schlüssel-Werte Paaren. Im nächsten Codeblock siehst du, wie ein solches dictionary aussehen könnte. Doch warum verwenden wir Klassen und Objekte anstelle eines dictionary?
Einerseits handelt es sich hier um ein OOP-Tutorial, v.a. wollen wir unsere Klasse aber noch erweitern. Zum Beispiel würde es Sinn machen, ein Attribute self.progress
hinzuzufügen. Dies könnte eine ganze Zahl sein, die den Lernfortschritt angibt: 0 (beherrsche Wort nicht), 1 (beherrsche Wort einigermassen), 2 (beherrsche Wort gut).
Auch werden wir sehen, dass Klassen Methoden (Funktionen) beinhalten können.
wordPairsDict = { 'One': 'Eins', 'Two': 'Zwei', 'Three': 'Drei' }
Aufgabe 2 (voci_trainer_v02)
Erstelle eine Kopie deiner ersten Version des Programs: voci_trainer_v02.py
Erweitere nun dein Programm um die folgenden Funktionalitäten:
- Tippt man ein falsches Wort ein, soll man mehrere Auswahlmöglichkeiten zum weiteren Vorgehen haben: (1) noch einma versuchen, (2) richtige Übersetzung anzeigen lassen, (3) nächstes Wortpaar
- Nach jeder Eingabe soll man die Möglichkeit haben, in der Konsole ein weiteres Wortpaar der Voci-Liste hinzuzufügen.
Aufgabe 3 (voci_trainer_v03)
Erstelle eine Kopie deiner letzten Version des Programs: voci_trainer_v03.py
.
Erweitere nun dein Programm um die folgenden Funktionalitäten:
- Wir wollen für jedes Wort den Lernfortschritt speichern. Erweitere die Klasse um das Attribut progress. Wird ein WordPair kreiert, soll der Fortschritt 0 sein (
self.progress = 0
):
class WordPair: def __init__(self,w1,w2): self.wordL1 = w1 self.wordL2 = w2 self.progress = 0
- Übersetzt man ein Wort (im ersten Anlauf) korrekt, so soll der Fortschritt um 1 erhöht werden.
- Gibt man ein Wort falsch ein, so soll der Fortschritt wieder um 1 zurückgestuft werden. Allerdings soll der Fortschritt nie kleiner als 0 sein.
- Sobald ein WordPair den Fortschritt
PROGRESS_MAX
erreicht hat, soll es nicht mehr abgefragt werden. - Füge dazu am Anfang deines Codes eine globale Konstante
PROGRESS_MAX = 3
. Wir verwenden hier Grossbuchstaben. Damit wollen wir andeuten, dass es sich hier um eine Konstante handelt, die nie verändert werden soll im Code.
Aufgabe 4 (Datenformate)
Im nächsten Schritt wollen wir die WordPairs aus Daten erzeugen, die wir aus Datenfiles einlesen. Typische Formate um Textdaten zu speichern, sind:
- CSV
- JSON
- (XML)
Bildet Gruppen (ca. 3 SuS) und arbeitet euch in eines der beiden Datenformate (CSV oder JSON) ein.
Auftrag:
- Arbeitet euch in euer Datenformat ein: Wie werden Daten damit gespeichert? Was sind die Besonderheiten? …
- Findet heraus, wie man mit Python solche Datenformate einlesen und schreiben kann.
- Erstellt ein Tutorial für eure Kollegen über euer Datenformat. Dieses soll einerseits eine allgemeine Einführung und Übersicht über euer Datenformat beinhalten. Andererseits soll genau erklärt werden, wie man mit Python mit diesem Format arbeiten kann.
- Euer Tutorial soll ein repräsentatives Beispiel einer Datei von Eurem Format beinhalten. Stellt dieses in eurem Eintrag den Anderen zur Verfügung (siehe Beispiel unten).
- Ebenso soll euer Tutorial ein Python-File beinhalten, mit dem dieses File gelesen und in dieses geschrieben werden kann (siehe ebenfalls Beispiel unten).
- Findet eine Website, auf der man Dateien eures Formats auf Gültigkeit prüfen kann.
- Ladet euer Tutorial auf dieses DokuWiki in eurem SuS Arbeitsbereich
- Erste (aber trotzdem gute) Version: Sonntag 24.11.2019
- Deadline: Montag 25.11.2019
Ein Codeblock im DokuWiki Editor wird wie folgt geschrieben:
<code python filename.py> for i in range(3): print(i) </code>
Dies sieht dann wie folgt aus:
- filename.py
for i in range(3): print(i)
Mit einem Klick auf den Filenamen kann das File dann direkt heruntergeladen werden. Wird kein Filenamen angegeben, so wird einfach der Code angezeigt, ohne dass man diesen hinunterladen kann.
Für andere Programmiersprachen oder Datenformate muss man die Definition entsprechend anpassen.
Beispiel JSON:
<code json filename.json> // füge hier die Daten im JSON Format ein </code>`
Beispiel C#:
<code csharp filename.cs> // C#: Console.WriteLine("Hallo Welt."); </code>`
Aufgabe 5 (voci_trainer_v04)
- Erstelle im Ordner
tutorial_oop_voci
einen Unterordnerdicts
.
- Erstelle darin mindestens vier Files, je zwei im CSV- und zwei im JSON-Format. Jedes File soll eine Wörtliliste zu einem Thema beinhalten, z.B.
animals_en_de.csv
,sport_fr_de.json
, … Jeder Eintrag soll beihalten:- Wort in Sprache 1
- Wort in Sprache 2
- Progress (z.B. Zahlen von 0 bis 3, wobei 0 für 'noch gar nicht gelernt' und 3 für 'komplett gelernt' stehen)
- Tipp: Mache eine Sicherheitskopie dieser Files, falls du sie aus Versehen überschreibst.
- Mache eine Kopie von deinem aktuellsten Voci Trainer und speichere diesen unter dem Namen
voci_trainer_v04.py
und bearbeite nun diese Datei.
- Erstelle nun eine neue Klasse Voci. Diese hat das Attribut WordPairList. Dies ist eine Liste, die alle zugehörigen WordPairs enthält. In seiner ursprünglichsten Form könnte diese Klasse so aussehen:
class Voci: def __init__(self,wpList): self.WordPairList = wpList
- Beim Programmstart soll dein Programm nun automatisch den Ordner
dicts
nach CSV, JSON und XML Files durchsuchen. Jedes gefundene solche File soll dann gelesen werden. Erstelle für jedes File ein Objekt der Klasse Voci und fülle die im File enthaltenen WordPairs in die zugehörige WordPairList.
Es gibt verschiedene Möglichkeiten, Files in einem Ordner zu suchen, z.B.:
import glob glob.glob("dicts/*.csv")
- Sobald die Daten geladen wurden, sollst du die Auswahl haben, welche Vociliste du lernen möchtest.
- Tipps:
- Das Programm soll funktionieren, egal wie viele Files du zum einlesen hast. Wie kannst du eine unbekannte Anzahl an Objekten der Klasse Voci kreieren?
- Das Programm wird allmählich lange und kompliziert. Definiere sinnvolle Funktionen, damit nicht aller Code im Hauptteil definiert ist.
Aufgabe 6 (voci_trainer_v04)
Erweitere deinen Code (vocitrainerv04.py) nun so, dass der Fortschritt in den Files gespeichert wird. Dein Code soll die Option haben, das Programm zu beenden. Bevor das Programm geschlossen wird, soll der Fortschritt gespeichert werden. Überschreibe dazu die bisherigen Voci-Wörtli-Files. Achte also darauf, dass die Files genau gleich geschrieben werden, wie sie eingelesen werden.
Tipp: Mache Kopien von deinen Voci-Listen, falls diese falsch oder leer überschrieben werden.
Aufgabe 7 (Console Game)
Auftrag: Als kleine Abschlussarbeit für dieses Semester sollt ihr ein Konsolen Game alleine oder in 2er Gruppen programmieren. Überlege dir auf nächste Woche (a) mit wem du arbeiten möchtest (oder alleine) und (b) was für ein Game es sein soll.
Die Bedingungen an das Game sind:
- Spielt in Konsole.
- Ihr dürft ein bereits bekanntes Spiel implementieren. Ihr könnt aber auch ein eigenes erfinden oder ein bestehende abändern/erweitern.
- Gibt nach erfolgreichem Spielen einen Score zurück: absolviertes Level und Anzahl Punkte (z.B. gesammelte Punkte, Spieldauer in Sekunden, Anzahl Versuche, …)
- Es ist auch möglich (und sogar wünschenswert), verschiedene Levels zu haben. Das Ziel wäre dann, ein möglichst hohes Level mit einem möglichst guten Score zu erzielen.
- Das Game wird selbständig und komplett von euch programmiert.
Theorie OOP II (Methoden, Vererbung)
Quellen:
Bisher haben wir Klassen und deren Objekte ausschliesslich dafür benutzt, um Daten zu speichern. Zum Beispiel haben wir alle Informationen, die zu einem Wortepaar (also das Wort in 2 Sprachen und den Progress) in einem Objekt vom Typ WordPair gespeichert. Klassen können aber noch viel mehr!
Wir haben gesehen, dass man in einer Klasse alle Informationen, welche zusammen gehören, speichern kann. Man kann aber einer Klasse auch Funktionalität hinzufügen.
OOP könnte man wie folgt kurz zusammenfassen: Das Grundkonzept der objektorientierten Programmierung besteht darin, Daten und deren Funktionen (Methoden), - d.h. Funktionen, die auf diese Daten angewendet werden können - in einem Objekt zusammenzufassen.
Methoden
Zum Beispiel könnten wir unsere Klasse WordPair wie folgt erweitern:
class WordPair: def __init__(self,w1,w2): self.wordL1 = w1 self.wordL2 = w2 self.progress = 0 def show_info(self): print(f"word language 1: {self.wordL1}, word language 2: {self.wordL2}, progress: {self.progress}") def increase_progress(self,max_progress): if self.progress < max_progress: self.progress += 1 def translation_correct_wordL1(self,value): if value == self.wordL1: return True else: return False def translation_correct_wordL2(self,value): if value == self.wordL2: return True else: return False
Die erste Methode (show_info) zeigt einfach alle Attribute der Klasse an. Nachdem wir ein Objekt dieser Klasse erstellt haben, können wir diese Methode aufrufen:
wp = WordPair("hubbub","Tohuwabohu",1) wp.show_info()
Die zweite Methode (increase_progress) ist spannender. Diese rufen wir auf, wenn wir den Progress um 1 erhöhen wollen. Dies soll aber nur dann geschehen, wenn nicht bereits das Maximum erreicht wurde. Beachte, dass dann jeweils noch der max. Progress übergeben werden muss, da diese Information nicht für jedes WordPair gespeichert wurde sondern ein Attribut in der Voci-Klasse ist.
wp = WordPair("hubbub","Tohuwabohu",1) wp.increase_progress(3)
Warum wollen wir den Progress mittels einer Klassen-Methode erhöhen und nicht direkt dort im Code wo das Wort abgefragt wird? Weil es Sinn macht, wenn man alle Logik, die WordPairs betrifft in die entsprechende Klasse hinein packt.
Die letzten beiden Methoden werden aufgerufen, wenn ein Input überprüft werden soll. Hat der Benutzer die korrekte Übersetzung eingegeben, so gibt diese Methode den Boolean True und ansonsten False zurück.
Überlege dir: Gibt es weitere Methoden, mit denen du die WordPair-Klasse sinnvoll erweitern kannst?
Vererbung
Ein wichtiges Konzept der OOP ist die Vererbung.
Machen wir ein Beispiel: In unserem Code haben wir eine Klasse Voci. Für jeder Datenfile, welches eine Wörtliliste enthält, erstellen wir ein Voci-Objekt. Nachdem wir die Wörtli gelern haben, wollen wir den Inhalt des Voci-Objekts zurück in die Datei schreiben. Es macht also Sinn, wenn die Voci-Klasse zwei Methoden read_file und save_file hat. Die Klasse könnte dann so aussehen:
class Voci: def __init__(self,file_path,max_progress): self.file_path = file_path self.max_progress = max_progress self.name = None self.WordPairList = [] self.language1 = None self.language2 = None def read_file(self): pass def save_file(self): pass
Das Problem ist nun aber: Wir haben insgesamt drei verschiedene Dateiformate. Das bedeutet also, dass die read_file und save_file-Methoden komplett anders aussehen, wenn wir ein CSV- oder ein JSON-File einlesen oder schreiben wollen.
Wir erstellen deshalb drei verschiedene Klassen: CSV_Voci, XML_Voci und JSON_Voci. Dies sollen drei eigene Klassen sein, alle sollen aber gleich aufgebaut sein, und zwar genau so wie die allgemeine Voci-Klasse. Deshalb sagen wir diesen drei neuen Klassen, dass sie von der Voci-Klasse erben sollen:
class CSV_Voci(Voci): def __init__(self, file_path,max_progress=3): super().__init__(file_path,max_progress) self.read_file() def save_file(self): pass def read_file(self): pass
- In der ersten Zeile geben wir eben an, dass CSV_Voci von Voci erben soll. Voci wird dann die parent class und CSV_Voci die child class genannt.
- Mit
super()
ist jeweils die parent class einer Klasse gemeint. Mitsuper().__init__(file_path,max_progress)
sagen wir deshalb, dass die__init__()
-Metode aus Voci verwendet werden soll.
- Instanziieren wir ein neues CSV_Voci Objekt, müssen wir den Pfad zum File und den max. Progress angeben:
voci = CSV_Voci('my_super_voci.csv',3)
.
- Mit
self.read_file()
lesen wir dann automatisch die Daten aus dem File ein.
- Speichern können wir dann einfach mit
voci.save_file()
.
- Betrachten wir nun die read_file-Methode. Beachte, dass diese sowohl in der parent class Voci wie auch in der child class CSV_Voci vorkommt:
def read_file(self): pass
- In der Voci-Klasse lassen wir diesen Code unverändert. Damit zeigen wir an, dass alle Klassen, die von Voci erben, eine solche Methode haben sollen. Da diese Methode für jede dieser child Klassen sehr unterschiedlich ist, kann diese Methode in der parent class noch nicht implementiert werden, wir schreiben einfach
pass
. Hingegen muss diese Methode in jeder child class wie CSV_Voci explizit implementiert werden.
- Analog für save_file
Aufgabe 7
Nun wollen wir uns an die finale Version unseres Codes machen. Bisher wurde der gesamte Code in ein einzelnes File hinein geschrieben. Damit der Code übersichtlich bleibt, macht es aber Sinn, diesen auf mehrere Files aufzuteilen. Erstelle dazu im Repo einen neuen Ordner, z.B. final, in dem wir die finale Version ablegen.
Erstelle darin einen Unterordner source und einen Unterordner dicts für alle Files mit Wörtlilisten. Erstelle dann folgende Files in der folgenden Struktur:
- app.py
- source/voci.py
- source/wordpair.py
- source/view.py
Schreibe deinen Code möglichst objektorientiert um.
Tipp: Kopiere deinen bestehenden Code nur in kleinen Päckchen in die neue Game-Struktur. Stelle immer sicher, dass der Code keine Fehler beinhaltet, bevor du dich um weiteren Code kümmerst.
Aufgabe 8
Finalisiere deinen Code.
- soll auswählen können, in welche Richtung man übersetzen möchte: wordL1 → wordL2 oder wordL2 → wordL1
- soll im Menu Editieren-Option haben, in der man jeweils für die WordPairs eines Vocis …:
- neue WordPairs hinzufügen kann
- bestehende WordPairs ändern kann
- bestehende WordPairs löschen kann
- den Progress aller WordPairs auf 0 zurücksetzen kann
- Soll eine neue Voci-Liste erstellen können. Diese wird dann im gewünschten Dateiformat gespeichert
- Überlege dir selbst, wie du dein Programm sinnvoll erweitern kannst.