Benutzer-Werkzeuge

Webseiten-Werkzeuge


de:beispiele

Beispiele

EAN-Prüfung

Tkinter/TTK

Die EAN-Prüfung ist ein Beispiel für eine einfache GUI-Anwendung. Sie hat ein Entry-Widget für die Eingabe einer EAN und ein Text-Widget für die mehrzeilige Ausgabe von Ergebnissen.

Für den Button „Prüfen“ wird diese Ereignismethode programmiert:

def bPruefen_Command(self):
    # Eingabe
    EAN = self.eEANCV.get()
    #Verarbeitung
    if not EAN.isdigit():
        self.ausgeben('Eine EAN darf keine anderen Zeichen als Ziffern enthalten!')
    if len(EAN) == 13:
        self.ausgeben('Länge der EAN: 13')
        self.ausgeben('Eingegebene Prüfziffer: ' + EAN[12])
        Summe = 0
        Index = 0
        Faktor = 1
        while Index < 12:
            Summe = Summe + int(EAN[Index])*Faktor
            Index = Index + 1
            if Faktor == 1:
                Faktor = 3
            else:
                Faktor = 1
        if Summe % 10 == 0:
            berechnetePrüfziffer = 0
        else:
            berechnetePrüfziffer = 10 - Summe % 10
        if int(EAN[12]) == berechnetePrüfziffer:
            self.ausgeben('Die Prüfziffer ' + EAN[12] + ' ist korrekt!')
        else:
            self.ausgeben('Die eingegebene Prüfziffer ' + EAN[12] + ' ist inkorrekt!')
            self.ausgeben('Die korrekte Prüfziffer ist ' + str(berechnetePrüfziffer))
    else:
        self.ausgeben('Die eingegebene EAN hat ' + str(len(EAN)) + ' Ziffern!')
        self.ausgeben('Sie muss aus 13 Ziffern bestehen.')

Gemäß dem EVA-Prinzip wird zunächst die Eingabe aus dem Entry-Widget eingelesen. Zum Einlesen benutzt man die dem Entry-Widget zugeordnete Kontrollvariable eEANCV. Ihr Wert kann zur Eingabe mit eENACV.get() gelesen und mit eEANCV.set(Wert) ausgegeben werden. Mit

    EAN = self.eEANCV.get()

wird also die in das Entry-Widget eingegebene EAN in die lokale str(ing) Variable EAN eingelesen und kann dann verarbeitet werden.

Im Verarbeitungsteil wird geprüft, ob 13 Ziffern eingegeben wurden und dann die Prüfziffernberechnung durchgeführt.

Die Ausgaben erfolgen in das Text-Widget mit der Bezeichnung Ausgabe. Es verfügt über sehr leistungsfähige Methoden, weswegen schon die Ausgabe einer einzelnen Zeile nicht ganz einfach ist. Für die Ausgabe wird daher eine eigene Methode ausgeben() benutzt, um die Programmierung zu vereinfachen.

def ausgeben(self, Zeile):
    self.Ausgabe.insert('end', Zeile + '\n')

Damit wird in das Text-Widget Ausgabe am Ende eine Zeile eingefügt und diese mit dem Steuerzeichen '\n' (NewLine) beendet. Besteht eine Ausgabezeile aus mehreren Teilstrings, so müssen diese mit „+“ zusammengesetzt werden. Zahlen müssen zuvor mittels str() in einen String umgewandelt werden.

Download:

Qt Variante der EAN-Prüfung

In Qt haben wir ein LineEdit-Widget für die Eingabe und ein PlainTextWidget für die Ausgabe. Um die EAN zu lesen, verwenden wir die Methode text() des LineEdit-Widgets.

    EAN = self.leEAN.text()

Die Ausgabe ist in Qt einfacher als in Tkinter/TTK:

    def output(self, line):
        self.Output.appendPlainText(line)

Download:

Auto

Dieses Beispiel eignet sich für die Einführung in die objektorientierte Programmierung. Es werden Tankanzeige und Kilometerstand eines Autos modelliert. Die eigentliche Modellierung findet mit dem Klassenmodellierer statt. Das Kennzeichen ist nicht unbedingt erforderlich, es dient zu leichteren Unterscheidung von Autos und zur Verwendung eines weiteren Datentyps.

Das Ergebnis kann interaktiv im UML-Fenster getestet werden. Dabei verstehen die Schülerinnen und Schüler den Unterschied zwischen den Konzepten Klasse und Objekt.

Im nächsten Schritt wird die Klasse Auto als Fachkonzept in einem GUI-Programm verwendet.

Das GUI-Programm nutzt die Auto-Klasse. Dazu muss diese importiert werden. Ein Auto wird erzeugt und als Attribut auto1 der GUI-Klasse zur weiteren Verwendung bereitgestellt.

from Auto import *
  ...
  self.auto1 = Auto('DA RR 1013', 47, 7.3)

Tkinter/TTK

Beim Tanken wird die in das Entry-Widget eingegebene Menge über die get()-Methode der zum Widget gehörenden Kontrollvariablen eMengeCV eingelesen und mittels float in den benötigten Datentyp konvertiert.

    def bTanken_Command(self):
        # Eingabe über die GUI
        Menge = float(self.eMengeCV.get())
        # Verarbeitung
        self.auto1.tanken(Menge)
        # Ausgabe
        self.anzeigen()

Dann wird gemäß dem EVA-Prinzip die eingegebene Menge in der Methode tanken() verarbeitet.

Abschließend erfolgt die Ausgabe des Ergebnisses in einer eigenen Methode anzeigen(). Die Werte für Kennzeichen, Tankinhalt und Kilometerstand werden über die get()-Methoden der Klasse Auto abgerufen und an die set()-Methoden der Kontrollvariablen eKennzeichenCV, eTankinhaltCV und eKilometerstandCV übergeben:

    def anzeigen(self):
        self.eKennzeichenCV.set(self.auto1.get_Kennzeichen())
        self.eTankinhaltCV.set(self.auto1.get_Tankinhalt())
        self.eKilometerstandCV.set(self.auto1.get_Kilometerstand())
        self.lAuto.place(x = self.auto1.get_Kilometerstand(), y = 160)

Dem Label-Widget lAuto wurde im Objektinspektor über das Attribut Image ein Auto-Bild zugewiesen. Mit der place()-Methode wird die x-Position des Autos auf den Kilometerstand gesetzt.

Download

Qt

Beim Tanken wird die eingegebene Menge über die text()-Methode des LineEdit-Widgets eingelesen und mittels float in den benötigten Datentyp konvertiert.

    def bTanken_clicked(self, checked):
        # Eingabe über die GUI
        Menge = float(self.leMenge.text())
        # Verarbeitung
        self.auto1.tanken(Menge)
        # Ausgabe
        self.anzeigen()

Dann wird gemäß dem EVA-Prinzip die eingegebene Menge in der Methode tanken() verarbeitet.

Abschließend erfolgt die Ausgabe des Ergebnisses in einer eigenen Methode anzeigen(). Die Werte für Kennzeichen, Tankinhalt und Kilometerstand werden über die get()-Methoden der Klasse Auto abgerufen und an die setText()-Methoden der der LineEdit-Widgets für Kennzeichen, Tankinhalt und Kilometerstand übergeben:

        self.leKennzeichen.setText(self.auto1.get_Kennzeichen())
        self.leTankinhalt.setText(str(self.auto1.get_Tankinhalt()))
        self.leKilometerstand.setText(str(self.auto1.get_Kilometerstand()))
        self.lAuto.move(self.auto1.get_Kilometerstand(), 160)

Dem Label-Widget lAuto wurde im Objektinspektor über das Attribut Pixmap ein Auto-Bild zugewiesen. Mit der move()-Methode wird die x-Position des Autos auf den Kilometerstand gesetzt.

Download

Verkettete Liste

Die Programmierung dynamische Datenstrukturen stellt eine erhebliche Herausforderung dar, denn man muss das Konzept der Verkettung mittels Verweisen verstehen und komplexe Operationen mit Verweisen durchführen. Neu dabei sind Variablen die Werte haben, welche Verweise auf Objekte bzw. Adressen sind.

In diesem Beispiel betrachten wir eine einfach verkettete lineare Liste. Die Liste selbst wird als Klasse VerketteteListe modelliert mit Knoten als Listenelementen. Als Attribut hat sie einen Verweis auf den Anfang der Liste.

Die Klasse Knoten kann im ersten Attribut Daten speichern kann und im Attribut Nächster den Verweis auf einen nächsten Knoten der verketteten Liste. Hat ein Knoten keinen nächsten Knoten, so erhält dieses Attribut den Wert None.

class Knoten:
    def __init__(self, Daten):
        self.Daten = Daten
        self.Nächster = None

Die Implementierung einer Einfügeoperation ist schwierig, weil vier Fälle zu unterscheiden sind:

  1. Die Liste ist leer.
  2. Es soll am Anfang eingefügt werden.
  3. Es soll am Ende eingefügt werden.
  4. Es soll zwischen zwei Knoten eingefügt werden.

Die beiden ersten Fälle lassen sich mit der Methode einfügen_AmAnfang() implementieren:

    def einfügen_AmAnfang(self, einKnoten):
        einKnoten.Nächster = self.Anfang
        self.Anfang = einKnoten

Im UML-Fenster lässt sich die Implementierung testen. Dazu erzeugt man eine verkettete Liste und einen Knoten, ruft über das Objekt verketteteliste1 die Methode einfügen_AmAnfang() auf und gibt für den Parameter einKnoten den Wert knoten1 an.

Zum Einfügen am Ende der Liste muss man sich mit einer Schleife und einer Cursor-Variablen zum letzten Element durchhangeln. Dort wird der neue Knoten angefügt.

    def einfügen_AmEnde(self, einKnoten):
        if self.Anfang is None:
            self.Anfang = einKnoten
        else:
            Cursor = self.Anfang
            while Cursor.Nächster is not None:
                Cursor = Cursor.Nächster
            Cursor.Nächster = einKnoten

Am schwierigsten ist das Einfügen vor einem Knoten, denn der neue Knoten muss dann hinter dem vorhergehenden Knoten eingefügt werden. Neben dem Cursor braucht man dazu einen weiteren Verweise auf den vorherigen Knoten. Der Knoten vor dem einfügt werden soll wird durch seine Daten bestimmt.

    def einfügen_vor(self, Daten, einKnoten):
        if self.Anfang.Daten == Daten:
            self.einfügen_amAnfang(einKnoten)
            return
 
        vorheriger_Knoten = self.Anfang
        Cursor = vorheriger_Knoten.Nächster
        while Cursor is not None and Cursor.Daten != Daten:
            vorheriger_Knoten = Cursor
            Cursor = Cursor.Nächster
        if Cursor is not None:
            einKnoten.Nächster = Cursor
            vorheriger_Knoten.Nächster = einKnoten
        else:
            raise Exception("Knoten mit Daten '%s' nicht gefunden" % Daten)

Vergleichbar schwierig ist das Löschen eines Knotens, denn zum Löschen muss der vorherige Knoten mit dem nachfolgenden verbunden werden.

    def löschen(self, Daten):
        if self.Anfang.Daten == Daten:
            self.Anfang = self.Anfang.Nächster
        else:
            vorheriger_Knoten = self.Anfang
            Cursor = vorheriger_Knoten.Nächster
            while Cursor is not None and Cursor.Daten != Daten:
                vorheriger_Knoten = Cursor
                Cursor = Cursor.Nächster
            if Cursor is not None:
                vorheriger_Knoten.Nächster = Cursor.Nächster

Durch interaktives Testen im UML-Fenster kann man die Funktionsfähigkeit der implementierten Methoden sehr gut prüfen, denn das Ergebnis wird unmittelbar im Objektdiagramm visualisiert. Man erkennt sofort, ob eine Methode wie gedacht funktioniert hat. Im Bild wurde zum Testen der löschen()-Methode die Liste mit den Elementen 'a, 'b' und 3 erzeugt und dann der Knoten mit Daten = 'b' gelöscht. Das hat funktioniert, denn die Liste besteht nur noch aus den beiden Elementen 'a' und 3.

Wichtiger Hinweis

Im UML-Fenster werden zur Identifizierung der Objekte deren Adressen benutzt. Im Beispiel also die Adresse 0x03350E98 für das Objekt knoten1.

>>> knoten1 = Knoten('a')
>>> print(knoten1)
<__main__.Knoten object at 0x03350E98>

Implementieren Sie daher keine __repr__-Funktion für ihre Klassen, weil diese Adressen dann nicht mehr zur Verfügung stehen.

Download:

de/beispiele.txt · Zuletzt geändert: 2022/08/25 21:33 von roehner