Seite 1 von 1

Probleme mit while-Schleife

Verfasst: Samstag 15. April 2023, 09:06
von LaurenceD
Hallo zusammen,

ich habe ein Problem mit folgender while-Schleife:

Code: Alles auswählen

      ....
        range=158
        position=0
        self.gauge1.SetRange(range)
        self.textParameter.Clear() #alter Feldinhalt löschen
        ser.write("get_para") #Kommando "Parameterliste anfordern"    
        while 1:
            Text = ser.readline()
            if not Text: break             
            self.textParameter.WriteText(Text)
            position += 1
            if position > 158: position = 158
            self.gauge1.SetValue(position)
        ser.close() #Schnittstelle schliessen
        Bemerkung="Anzahl der Zeilen: " + str(position)
        self.textParameter.WriteText(Bemerkung)
        ....
Die Daten werden zwar eingelesen und im wxTextCtrl-Feld "textParameter" gespeichert, aber auf dem Bildschrim wird der Inhalt erst nach dem "break" aktuallisiert. Schlimmer ist aber, daß die Variable "position" nicht weiter zählt und in weiterer Folga auch die Verlaufsanzeige (gauge) nicht funktioniert. Der Wert der Variable "position" beträgt am Schluß definitiv 1.

Hat jemand eine Idee wieso obiger Code nicht funktioniert?

Re: Probleme mit while-Schleife

Verfasst: Samstag 15. April 2023, 09:22
von __deets__
Ein Klassiker. GUIs laufen Ereignisbasiert. Auf Ereignisse verschiedenster Art - Klicks, Bewegungen der Maus, Timer - läuft *kurz* Code, der eine Änderung des GUI Zustandes hervorruft. Und dann kehrt die Ausführung in die Hauptschleife zurück, welche die Änderungen sichtbar macht. Ein dauerhaftes ausführen von Code wie bei dir verträgt sich damit nicht.

Der Code muss also umgeschrieben werden. Am einfachsten auf eine Timer-basierte Lösung. Schau in die Dokumentation deines UI-Toolkits, da sollten Beispiele angegeben sein.

Re: Probleme mit while-Schleife

Verfasst: Samstag 15. April 2023, 11:11
von sparrow
@LaurenceD: Weitere Anmerkungen zum Code:

1 ist ein schlechter Ersatz für True. Es müsste also `while True:` heißen.

Namen schreibt man in Python klein_mit_unterstrich (ausgenommen sind Klassen (PascalCase) und Konstanten (KOMPLETT_GROSS).
Also `text` nicht `Text`.

Ich finde es als verwirrend, mehr als eine Anweisung in eine Zeile zu schreiben.

Code: Alles auswählen

if not text: break 
ist viel unverständlicher als

Code: Alles auswählen

if not text:
    break 
Statt

Code: Alles auswählen

position += 1
if position > 158: position = 158
würde ich wie folgt vorgehen:

Code: Alles auswählen

if position  < 158:
    position += 1
Da du das mit jedem Durchgang hoch zählst und mit 0 startest, weißt du ja, dass es keinen Wert über 158 annehmen kann. Da kann man sich das nicht hübsche und sinnlose Addieren von 1 zu Position sparen, wenn es nicht mehr nötig ist.

Re: Probleme mit while-Schleife

Verfasst: Samstag 15. April 2023, 12:13
von Sirius3
Du scheinst ja eine Serielle Schnittstelle abzufragen. Da wundert es mich, dass Du den Befehl nicht mit einem Neue-Zeile-Zeichen abschließen mußt.
Woher kommen die 158? Du scheinst ja auch einen Timeout zu setzen, weil sonst dürfte readline niemals einen leeren String zurückliefern. Das ist aber keine stabile Methode. Gibt es denn kein anderes Merkmal, wie Du erkennen kannst, dass die Übertragung fertig ist?

Nun darf es bei GUI-Programmen keine langlaufenden Schleifen oder blockierende Aufrufe wie readline geben.
Eine Lösung wäre es, das Lesen der seriellen Schnittstelle in einen Thread auszulagern und dann mit Events mit der GUI zu kommunizieren: https://wiki.wxpython.org/LongRunningTasks

Re: Probleme mit while-Schleife

Verfasst: Samstag 15. April 2023, 12:23
von __blackjack__
@LaurenceD: Ergänzend zu den vorherigen Anmerkungen: Namen sollten nicht nummeriert werden. Dann will man entweder bessere Namen, oder gar keine Einzelnamen und -werte sondern eine Datenstruktur. Oft eine Liste.

`range` ist der Name des eingebauten `range`-Datentyps, den Namen sollte man deshalb nicht an etwas ganz anderes binden.

Auch bei dem späteren Vergleich sollte die Variable verwendet werden und nicht noch einmal hart kodiert die 158. Wenn man der Wert mal anpassen möchte, sollte man das nur an *einer* Stelle tun müssen.

Aus der ``while``-Schleife würde sich mit `iter()` eine ``for``-Schleife über die Zeilen machen lassen, aber selbst diesen Umweg muss man nicht gehen, weil man direkt über das `Serial`-Objekt iterieren kann.

Statt `position` ”von Hand” hoch zu zählen, könnte man die `enumerate()`-Funktion verwenden und mit `max()` den Wert für die Anzeige begrenzen.

`Serial`-Objekte sind Kontextmanager, da sollte man also ``with`` verwenden, statt `close()` selbst aufzurufen und zu hoffen, dass der Programmfluss da in jedem Fall vorbeikommen wird.

`ser` ist auch kein besonders sinnvoller, verständlicher Name für ein `Serial`-Objekt.

Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.

Ungetestet:

Code: Alles auswählen

        with Serial(...) as connection:
            ...
            max_position = 158
            self.gauge.SetRange(max_position)
            self.text_parameter.Clear()
            connection.write("get_para")  # Kommando "Parameterliste anfordern"
            position = 0
            for position, text in enumerate(connection, 1):
                self.text_parameter.WriteText(text)
                self.gauge.SetValue(max(position, max_position))
                self.text_parameter.WriteText(f"Anzahl der Zeilen: {position}")
        ...