Hauptprogramm mit tkinter/canvas soll div. Unterprogramme aufrufen und deren Ergebnisse grafisch anzeigen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
__MiB__
User
Beiträge: 7
Registriert: Sonntag 8. September 2024, 19:07

Ziel:

Umfangreiche Klimadaten erfassen und auf einem Display (HDMI) darstellen, z. T. mit Verlaufskurve.

Zum Testen habe ich 2 Python3 Scripte erstellt:
1. dieses erfasst die Daten eines BME280 und stellt sie in der Ausgabekonsole von thonny dar, diese werden alle 5 Sekunden aktualisiert.
2. dieses ermittelt die aktuelle Zeit/Datum und stellt sie in der Ausgabekonsole dar, Aktualisierung alle 1 Sekunde.
3. Soll ein Script mit tkinter/canvas werden, das die beiden ersten aufruft und die Daten jeweils in einem Frame mit Label darstellt.

Problem, Fragen:

Grundsätzlich habe ich das Problem, wie ich die beiden "Unterprogramme" in dem Hauptscript aufrufe und ausführe sowie die dort erzeugten Daten auslese (einer Variablen zuordnen?) und in einem im Hauptprogramm mit tkinter erzeugten und formatierten Fenster anzeige.

Das ist in diesem Falle nur ein kleineres Projekt, um die Vorgehensweise zu verstehen. Später soll auch in einzelnen "Unterprogrammen" UV-Index, Windgeschwindigkeit und -richtung, Niederschlag, die Daten einer Photovoltaik-Inselanlage u.s.w. erfasst und dargestellt werden, die Implementierung einer Datenbank ist auch vorgesehen, steht aber programmiertechnisch noch in weiter Ferne, da ich kein Programmierprofi bin und die Aufgaben nacheinander angehen will.

Vioelleicht kann hier jemand die grundlegende Vorgehensweise darstellen, mit der ich an die Sache herangehen kann...

Irgendwie finde ich im Web auch kein Beispiel, in dem dies gezeigt wird, oder ich habe die richtigen Seiten noch nicht gefunden.
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@__MiB__: Konsolenprogramme und GUI-Programme funktionieren grundsätzlich anders was den Programmablauf betrifft. Bei Konsolenprogrammen schreibst Du Schleifen die den Programmablauf steuern und kannst beispielsweise blockierend auf Daten warten oder einfach nur `time.sleep()` benutzen um zu warten. Bei GUIs muss immer die GUI-Hauptschleife laufen und Dein Code darf wenn er von der GUI-Hauptschleife aufgerufen wird, immer nur sehr kurz etwas machen und muss dann zurückkehren. Denn solange Dein Code etwas macht friert die GUI ein, aktualisiert sich nicht mehr und reagiert nicht mehr auf den Benutzer.

Bei GUIs schreibt man Code der die GUI erzeugt, registriert Rückruffunktionen die bei bestimmten Ereignissen aufgerufen werden sollen, und ruft dann die GUI-Hauptschleife auf. Ereignisse können Benutzereingaben, das klicken auf Schaltflächen, aber auch das ablaufen einer Verzögerung sein. Für letzteres hat Tk die `after()`-Methode auf Widgets, wo man eine Rückruffunktion und eine Zeit in Millisekunden (und optional Argumente für die Rückruffunktion) angeben kann. Die Funktion wird dann (frühestens) nach Ablauf der Zeit von der Hauptschleife aufgerufen, sollte dann kurz etwas machen, und wieder zurückkehren.

Einfaches Beispiel für eine Uhr:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from datetime import datetime as DateTime


def update_clock(label):
    label["text"] = DateTime.now().strftime("%H:%M:%S")
    label.after(500, update_clock, label)


def main():
    root = tk.Tk()
    clock_label = tk.Label(root)
    clock_label.pack()
    update_clock(clock_label)
    root.mainloop()


if __name__ == "__main__":
    main()
Hier kommt man noch ohne objektorientierte Programmierung (OOP) aus, aber je mehr Argumente man bei den Aufrufen durchreichen muss, um so unübersichtlicher wird das. Nicht-triviale GUIs brauchen eigene Klassen in denen man sich Zustand über Aufrufe hinweg merken kann.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
__MiB__
User
Beiträge: 7
Registriert: Sonntag 8. September 2024, 19:07

Hi
Ich habe die Lösung des Aufrufs der Unterprogramme gefunden!

War recht einleuchtend erklärt in einem Video!

https://www.youtube.com/watch?v=7N3tkBryXGQ

Finde ich super, mal schauen, ob ich damit weiter komme :)
Benutzeravatar
sparrow
User
Beiträge: 4501
Registriert: Freitag 17. April 2009, 10:28

@__MiB__: Wie genau hilft ein Video weiter, das shutil beschreibt? Das ist das Modul für File-Operationen.

Ich vermute, dass du denkst, dass das eine Programm das andere tatasächlich ausführt. Das ist in 99% der Fälle falsch (und dein Programm gehört nicht zu den 1%).
Man ruft aus einem Python-Programm kein anderes Python-Programm auf. Man importiert es als Modul und nutzt dessen Funktionen, Klassen, etc.

Wenn du etwas mit GUI machen willst, musst du GUI lernen. Die Hinweise kamen von __blackjack__.
__MiB__
User
Beiträge: 7
Registriert: Sonntag 8. September 2024, 19:07

@__blackjack__

Vielen Dank für den Tipp!

Werde ich beherzigen.

Es soll aber so sein, das wenige Eingaben erforderlich sein werden. Es soll wie auf einer Wetterstation möglichst viel Info angezeigt werden und nur ggf. ausgewählt werden, welcher Datensatz als nächstes dargestellt werden soll. z. B. Screen1: Wetterdaten und Screen2 Daten der Solar/Windkraftanlage, Ladezustand Batterien, Verbrauch, u. s. w. , sowie zukünftig Screen3 Datenhistorie wie Maximal- und Minimalwerte in bestimmten Zeiträumen

Ich arbeite zunächst mal mit den gewonnenen Erkenntnissen und sehe dann mal weiter!
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@__MiB__: In dem Video ist ziemlich sicher keine Lösung für das Problem, denn das geht um das `os`-Modul. Für Pfade benutzt man das nicht mehr, denn es gibt das `pathlib`-Modul dafür und `os.system()` ist schon lange durch das `subprocess`-Modul abgelöst. Aber auch das ist keine Lösung wenn man nicht tatsächlich externe Programme hat, statt eigenen Code den man in *ein* Programm zusammenfassen kann.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Sirius3
User
Beiträge: 18215
Registriert: Sonntag 21. Oktober 2012, 17:20

@__MiB__: es bleibt dabei, bei GUI-Programmen muß man auf Ereignisse reagieren, Ereignisse können Nutzereingaben sein, aber auch die Zeit, die vergeht. `after` hat __blackjack__ ja schon angesprochen.
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Habe mir das Video jetzt mal angeschaut. Es wird gar nicht auf `os.system()` eingegangen, sondern wirklich nur auf Operationen mit Dateipfaden. Inhaltlich wie gesagt seit `pathlib` veraltet.

Zwei Fehler im Video: Die Behauptung `os.path.exists()` ist für „Files“ während `os.path.isdir()` für Verzeichnisse ist, ist falsch. Es gibt ja auch `os.path.isfile()`, da sollte einem auffallen, das die Aussage komisch ist. `os.path.exists()` ist ganz generell für Pfade, sowohl Verzeichnisse wie auch Dateien.

Und ``dirpath.split("\\")`` ist Murks, weil er ja selbst sagt, das man `os.path.join()` verwenden sollte, weil das Trennzeichen vom Betriebssystem abhängig ist. Das gilt natürlich nicht nur für das Zusammensetzen von Pfaden, sondern auch für das trennen.

Ausserdem muss man den \ nicht verdoppeln weil das ein regulärer Ausdruck ist, was im Video behauptet wird.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
__MiB__
User
Beiträge: 7
Registriert: Sonntag 8. September 2024, 19:07

OK, danke für die Beitrage, dann werde ich mich noch weiter damit befassen. Vielleicht finde ich jemanden, der mir anhand von Beispielen erklären kann, wie das alles funktioniert, mit dem Programmieren tue ich mich leider etwas schwer.
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

dann musst du spezifische Fragen mit deinem Code stellen und dann kann man dir sagen, warum das nicht so geht, wie du es gerne hättest.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
DeaD_EyE
User
Beiträge: 1205
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__blackjack__ hat geschrieben: Sonntag 15. September 2024, 13:32 Ausserdem muss man den \ nicht verdoppeln weil das ein regulärer Ausdruck ist, was im Video behauptet wird.
Die Erklärung ist falsch, aber der Grund wieso er das tut, ist die Nutzung der Backslashes.
\r \n usw. werden in nicht druckbare Steuerzeichen umgewandelt. Bei "C:\Users\USERNAME\neu.txt" würde dann \n durch Newline ersetzt.

Wenn man einfach die normalen Schrägstriche als Pfadtrenner verwendet, hat man das Problem nicht.
Und pathlib verwenden....

EDIT: Hat aber nichts mit dem eigentlichen Problem zu tun. Man kann eine GUI programmieren, die z.B. über Threads Messwerte von Sensoren holt, diese in eine Queue packt und die Mainloop der GUI kann dann Elemente aus der Queue holen anzeigen. Wenn die Queue leer ist, dann einfach kein Update der Labels machen. Dass die GUI-Anwendung im Hintergrund weitere Prozesse startet, ist nicht unbedingt eine gute Lösung. Eine Alternative wäre MQTT, dass unter andrem zur Übertragung von Sensor-Werten verwendet werden kann. Dafür benötigt man dann aber einen MQTT-Broker und die App ist somit nicht mehr eigenständig.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten