Anfängerfrage: Kombination GUI, Threading, Queue umsetzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo
Ich bastle gerade - und das sollte man ja bekanntlich nicht :lol:

So richtig tolle ganzheitliche Beispiele findet man nicht zum genannten Thema (zumindest ich nicht) für Hinweise wäre ich sehr froh.
Den Code unten habe ich zum grossen Teil gefunden und dann versucht für mich zu ergänzen. Das mit der Übergabe der Queue's muss doch anders gehn - oder?
Zur Info: Dort wo die Counter Upgedatet werden, soll später der Code hin, welcher Daten von der Seriellen Schnittstelle liest.

Wäre toll, wenn jemand den Code mal ansieht und vorallem Böck und Bastelleien aufzeigt. Oder ob der so im grossen und ganzen "gut" ist. Perfekt muss er nicht sein. Man findet immer was - es geht mir ums Grundprinzip.

Wie schon erwähnt: Mich würde auch grössere Projekte interessieren vorallem mit GUI wie die Aussehen, Struktur usw. Wenn ihr welche kennt - gerne. Allenfalls auch als Datei(en) über PN.

Danke schon mal.

Code: Alles auswählen

import tkinter as tk
from time import sleep
from threading import Thread
from queue import Queue
from serial import Serial


class GuiPart:
    def __init__(self, master, queue, endCommand):
        self.queue = queue

        # Set up the GUI
        self.lbl1 = tk.Label(master, text='Counter 1')
        self.lbl1.pack()
        self.lbl2 = tk.Label(master, text='Value 1')
        self.lbl2.pack()
        self.lbl3 = tk.Label(master, text='Counter 2')
        self.lbl3.pack()
        self.lbl4 = tk.Label(master, text='Value 2')
        self.lbl4.pack()
        self.lbl5 = tk.Label(master, text='Counter 3')
        self.lbl5.pack()
        self.lbl6 = tk.Label(master, text='Value 3')
        self.lbl6.pack()
        self.btn_close = tk.Button(master, text='Close', command=endCommand)
        self.btn_close.pack()

    def processIncoming(self):
        """Handle all messages currently in the queue, if any."""
        while self.queue.qsize():
            try:

                # Check contents of message and do whatever is needed. As a
                # simple test, print it (in real life, you would
                # suitably update the GUI's display in a richer fashion).

                msg1 = self.queue.get(0)
                msg2 = self.queue.get(0)
                msg3 = self.queue.get(0)

                self.lbl2.config(text= msg1)
                self.lbl2.update()
                self.lbl4.config(text= msg2)
                self.lbl4.update()
                self.lbl6.config(text= msg3)
                self.lbl6.update()

            except queue.Empty:
                # just on general principles, although we don't
                # expect this branch to be taken in this case
                pass

class ThreadedClient:
    """
    Launch the main part of the GUI and the worker thread. periodicCall and
    endApplication could reside in the GUI part, but putting them here
    means that you have all the thread controls in a single place.
    """
    def __init__(self, master):
        """
        Start the GUI and the asynchronous threads. We are in the main
        (original) thread of the application, which will later be used by
        the GUI as well. We spawn a new thread for the worker (I/O).
        """
        self.counter1 = 100
        self.counter2 = 200
        self.counter3 = 300

        self.master = master

        # Create the queue
        self.queue = Queue()

        # Set up the GUI part
        self.gui = GuiPart(master, self.queue, self.endApplication)

        # Set up the thread to do asynchronous I/O
        # More threads can also be created and used, if necessary
        self.running = 1
        self.thread1 = Thread(target=self.workerThread1)
        self.thread1.start()

        # Start the periodic call in the GUI to check if the queue contains
        # anything
        self.periodicCall()

    def periodicCall(self):
        """
        Check every 200 ms if there is something new in the queue.
        """
        self.gui.processIncoming()
        if not self.running:
            # This is the brutal stop of the system. You may want to do
            # some cleanup before actually shutting it down.
            import sys
            sys.exit(1)
        self.master.after(200, self.periodicCall)

    def workerThread1(self):
        """
        This is where we handle the asynchronous I/O. For example, it may be
        a 'select(  )'. One important thing to remember is that the thread has
        to yield control pretty regularly, by select or otherwise.
        """

        while self.running:
            # To simulate asynchronous I/O, we create a random number at
            # random intervals. Replace the following two lines with the real
            # thing.
            sleep(1)
            self.counter1 += 1
            self.counter2 += 1
            self.counter3 += 1
            self.queue.put(self.counter1)
            self.queue.put(self.counter2)
            self.queue.put(self.counter3)

    def endApplication(self):
        self.running = 0

root = tk.Tk()
root.geometry('170x200+30+30')

client = ThreadedClient(root)
root.mainloop()
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

also grundsätzlich ist die Kombination von GUI + Thread nicht trivial. Grund: der Mainloog des GUI-Frameworks braucht die Kontrolle, damit die GUI reagiert und der Thread muss parallel dazu laufen.

Ein einfacheres Beispiel - IMHO auch definitiv deutlich einfacher als deines - findest du hier.

Für "größere" Sachen würde ich aber auch eher Qt als Framework nehmen. Da kannst du Komponenten der GUI über Signals und Slots einfacher verknüpfen, außerdem kennt Qt eine eigene Klasse für Threads, welche du einfacher in den Mainloop integrieren kannst.

Gruß, noisefloor
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Dir steht einiges auf dem Kopf. In der GUI sollte eigentlich die Steuerung der anderen Programmteile stattfinden, Du steuerst aber die GUI aus der Datensammelklasse heraus.
Wie verquer ist, zeigt sich daran, dass Du endApplication in der Datensammelklasse
über einen Knopf der GUI aufrufst, um dann ein Flag in der Datensammelkasse zu setzen, das wiederum in einer Methode, die regelmäßig über die GUI aufgerufen wird zu prüfen und dort dann das Programm zu beenden.
Ein einfacher Ende-Knopf führt also zu 5 Sprüngen zwischen den Welten.

Wenn man anfängt Variablen durchzunummerieren, will man eigentlich Listen verwenden.
Label sollte man sich gar nicht merken müssen, den Inhalt eines Labels ändert man am besten über StrVar oder hier ein IntVar-Objekt.
Statt drei Dinge immer einzeln in die Queue zu stecken, solltest Du ein 3er-Tuple verwenden.
Importe sollte immer am Anfang stehen und sys.exit gar nicht verwendet werden. Hier reicht ein destroy des Tk-Objekts.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo zusammen
Danke für eure Antworten.
@Sirius3: Das habe ich eben vermutet, dass das so diverses nicht clever ist. Ihr seht sowas ziemlich rasch ich hab den Durchblick da noch nicht.

Denke der Link von noisefloor ist nicht schlecht?! Werde wohl darauf aufbauen?!

Ist Python eingentlich für grössere Sachen (1000 bis 2000 Zeilen) mit GUI, Datenbankanwendung, Filehandling etc. geeignet - mit vernünftigem Aufwand? Wartbarkeit nach einigen Monaten?
Habe vor kurzem einen Artikel gelesen, wo für solche Projekte Python dermasen schlecht ins Licht gerückt wurde. Der Autor war wohl nicht Python-Fan. Hat er ev. ein bisschen recht?

Bin nämlich gerade an dem Punkt wo ich überlege mein Projekt mit andern Sprachen / Tools weiter zu führen. z.B. Visual Studio oder C++ Builder oder Delphi von emarcadero. Delphi kannte ich mal recht gut war aber vor etwa 15 Jahren. Plattformübergreifende Entwicklung wäre nicht schlecht. Das bieten ja die letzt genannten Tools. Die Tools sind teilweise nicht mehr gratis, dafür können sie auch einiges.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ist Python eingentlich für grössere Sachen (1000 bis 2000 Zeilen) mit GUI, Datenbankanwendung, Filehandling etc. geeignet - mit vernünftigem Aufwand?
Ja, natürlich. Mal abgesehen davon, dass 1000 - 2000 Zeile jetzt auch nicht sooo viel ist.

Es gibt wesentlich größere Sachen, die in Python geschrieben sind. Dropbox verwendet z.B. viel Python, der Audio-Player Quod Libet ist in Python geschrieben und größere, auf Django-basierende Webprojekte haben auch locker (viel) mehr Zeilen.
Wartbarkeit nach einigen Monaten?
Das hängt wohl in erster Linie davon ab, wo gut du deine Code strukturierst und dokumentierst. Schlechten Code kann man in jeder Sprache schreiben ;-)

Gruß, noisefloor
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

kussji hat geschrieben: Samstag 23. Juni 2018, 16:55 Ist Python eingentlich für grössere Sachen (1000 bis 2000 Zeilen) mit GUI, Datenbankanwendung, Filehandling etc. geeignet - mit vernünftigem Aufwand? Wartbarkeit nach einigen Monaten?
Habe vor kurzem einen Artikel gelesen, wo für solche Projekte Python dermasen schlecht ins Licht gerückt wurde. Der Autor war wohl nicht Python-Fan. Hat er ev. ein bisschen recht?
Die einzige vernünftige Antwort die man auf so eine Frage wohl geben kann ist doch: es kommt drauf an. Das größte was ich bis dato in Python geschrieben habe war eine Art Smart-Home-App (ca. 2,5k Zeilen), allerdings ohne GUI sondern mit Webinterface.
kussji hat geschrieben: Samstag 23. Juni 2018, 16:55Bin nämlich gerade an dem Punkt wo ich überlege mein Projekt mit andern Sprachen / Tools weiter zu führen. z.B. Visual Studio oder C++ Builder oder Delphi von emarcadero. Delphi kannte ich mal recht gut war aber vor etwa 15 Jahren. Plattformübergreifende Entwicklung wäre nicht schlecht. Das bieten ja die letzt genannten Tools. Die Tools sind teilweise nicht mehr gratis, dafür können sie auch einiges.
Für wen soll dein Projekt denn "wartbar" sein, wenn du im selben Atemzug Delphi erwähnst ? ;-) Ich nutze z.B. Rust wenn ich das Gefühl habe, Python geht irgendwo die Puste aus. Ein größeres Projekt nur in einer Sprache zu entwickeln ist doch eher selten.
When we say computer, we mean the electronic computer.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

kussji hat geschrieben: Samstag 23. Juni 2018, 16:55 Ist Python eingentlich für grössere Sachen (1000 bis 2000 Zeilen) mit GUI, Datenbankanwendung, Filehandling etc. geeignet - mit vernünftigem Aufwand? Wartbarkeit nach einigen Monaten?
Die Wartbarkeit ist nicht zuletzt eine Frage des Programmdesigns und Python unterstützt gutes Programmdesign (das kommt allerdings nicht von alleine, sondern erfordert Erfahrung – egal in welcher Programmiersprache). Projekte mit 200.000 Zeilen und auch deutlich mehr sind mit Python kein Problem.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo zusammen
Noch so ein paar ermunternde Worte und ich bleibe euch noch ein bischen erhalten in diesem Forum :lol: 8)
Vielleicht sogar so lange, bis ich auch eure Fragen beantworten kann :) .

Mit Angabe der Anzahl Zeilen, wollte ich nur ein wenig mitteilen, was ich unter "gross" verstehe. Es gibt sicher Programme die mit X-facher grösse problemlos laufen.
Und in der Tat - schlechte Programme schreiben, kann Mann in jeder Sprache :mrgreen:

Gibt es weitere interessante bekanntere Programme die mit Python realisiert sind? Was realisiert ihr damit ausser z.B. auf einem Raspi ein LED blinken zu lassen.
Und meine Frage bleibt ein wenig offen. Gesamtprojekte findet man kaum. Teilweise verständlich. Aber wie lernt man den geschickten Zusammenbau etwas Umfangreicher Programme. Denke alle 1000 Zeilen in ein Programm sind nicht so clever. Gibt es Struktur-Vorlagen?
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kussji: Ich setze Python beruflich für so viel wie möglich ein. Grösse der Programme ist verschieden, je nach dem ob das nur eine kleine Aufgabe erledigt, ”glue code” ist der andere Programme/Systeme verbindet, oder grössere (Web)anwendung. Das grösste, akuelle Projekt sind ca. 12.000 Zeilen (Unit-Tests nicht mitgerechnet). Wobei ich Kommentare und DocStrings da jetzt mitgezählt habe (simples `wc --lines` über die *.py-Dateien). Andererseits kommen da auch noch HTML und JavaScript dazu und die Anwendung nutzt auch noch andere Software von Drittanbietern, die in anderen Programmiersprachen geschrieben ist (unter anderem Perl und Java) um ihre Aufgabe(n) zu erledigen.

1000 Zeilen in einem Modul ist so die Obergrenze an der ich persönlich den Drang verspüre das auf mehr als ein Modul aufzuteilen. Das grösste Modul im oben genannten Projekt hat ungefähr 1.800 Zeilen. Das könnte ich zwar aufteilen, und werde das auch irgendwann tun, aber ich sehe in dem konkreten Fall keinen grossen Vorteil, darum hat das erst einmal keine hohe Priorität.

Das gute an Python-Packages und Modulen ist, das man die auch dann anfangen kann aufzuteilen wenn es zu gross wird. Ich würde also nicht anfangen ein Projekt was noch kaum Code hat, auf zig Module zu verteilen, weil das ja irgendwann mal grösser wird.

Wikipedia hat eine Liste: https://en.wikipedia.org/wiki/List_of_Python_software

Mir wären so auf Anhieb Calibre, Mercurial, MoinMoin-Wiki, Sphinx, Sublime Text, und Vim eingefallen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

kussji hat geschrieben: Samstag 23. Juni 2018, 18:38 Gibt es weitere interessante bekanntere Programme die mit Python realisiert sind? Was realisiert ihr damit ausser z.B. auf einem Raspi ein LED blinken zu lassen.
Wir setzen für unsere Backend-Entwicklung hauptsächlich Java ein, große Projekte mit zig tausend Zeilen Code die mehr und mehr durch kleinerer Python-Services abgelöst werden. Bei letzterem hast du einen simplen Restservice mit 200-300 Zeilen in einem leichgewichtigen Framework wie bspw. Tornado schnell geschrieben. Bei Java schaut das weniger entspannt aus.

Es gibt wahnsinnig viel Server-basierte Software die in Python geschrieben ist, z.B. Check_MK für Monitoring, Salt für automatisierte Software-Deploys oder der Paket-Manager `Portage` in Gentoo. Die Linux-Distribution `Ubuntu` wurde teilweise auch in Python geschrieben. Youtube ebenso. Dropbox auch.
When we say computer, we mean the electronic computer.
kussji
User
Beiträge: 78
Registriert: Mittwoch 16. Mai 2018, 09:58

Hallo
Danke Euch für die Offenbarungen. Interessant. Und ermunternd Python doch besser kennen zu lernen.
Antworten