Ein GUI und ein Skript verbinden

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
pixewakb
User
Beiträge: 1413
Registriert: Sonntag 24. April 2011, 19:43

Verständnisfrage (sorry, falls ich inzwischen nerve :( ) bzw. eine Frage zur technischen Machbarkeit:

Aktuelle Situation: Ich möchte ein Python-Skript (pyw) mittels Autostart laufen lassen, das zeitgesteuert bestimmte Aufgaben erledigt. Wenn ein Zeitpunkt t eintritt, soll das Skript eine Aufgabe erledigen. Damit der Benutzer in dieser Zeit den Rechner nicht herunterfährt, soll dann ein Fenster aufpoppen, das über den Vorgang informiert, in einem plainTextEdit-Feld den Vorgang dokumentiert und nach Abschluss der Arbeit selbstständig verschwindet oder aber vom Benutzer geschlossen werden kann.

Meine Frage: Wie verbinde ich sinnvoll mein Skript mit dem GUI? Ich arbeite aktuell wieder mit PyQt, nachdem ich das seit gut einem Jahr nicht mehr machen musste. Seinerzeit war das GUI Ausgangspunkt meiner Überlegung, d. h. über Signale habe ich Prozesse im GUI angeschoben, d. h. ein Klick auf den Button x bewirkte, dass Eingaben abgefragt und Inhalte von Steuererlemente geändert wurde.

Aktuell möchte ich aber den umgekehrten Weg, d. h. ein Skript läuft im Hintergrund und ändert bei Bedarf Inhalte des GUI. Ist das technisch machbar und wenn ja, wie macht man das konzeptionell? Normalerweise würde ich das GUI in eine Klasse packen und dort Änderungen durch Methoden abfangen, wie aber kann ich von außen auf das GUI zugreifen, d. h. aus meinem "Hauptprogramm".

Danke für die Geduld mit mir und die vielen guten Hinweise!!!
Benutzeravatar
pixewakb
User
Beiträge: 1413
Registriert: Sonntag 24. April 2011, 19:43

Anfrage hat sich erst einmal erledigt!!!

Wahrscheinlich habe ich einen Ansatz gefunden, der laufen könnte. :!:

Ich will das erst noch einmal testen! :wink:
BlackJack

@pixewakb: Statt ein Fenster zu öffnen was sich plötzlich in den Vordergrund drängelt und den Benutzer nervt, oder aber im Hintergrund aufgeht wo es nicht wahrgenommen wird, verwendet man für so etwas in der Regel ein `QSystemTrayIcon`. Da kann man eine Nahricht als Sprechblase aufpoppen lassen, das Icon ändern wenn das Programm aktiv ist, und der Benutzer kann auch draufklicken und dann zum Beispiel das Fenster mit den Fortschrittsinformationen zu sehen. Man kann ausserdem ein Kontextmenü hinterlegen wenn man dem Benutzer noch mehr Möglichkeiten bieten möchte als einfaches draufklicken.
Benutzeravatar
pixewakb
User
Beiträge: 1413
Registriert: Sonntag 24. April 2011, 19:43

Wie genau verbinde ich dann mein Skript mit der Programmlogik mit dem GUI. Das ist aktuell für mich das Problem, weil ich gerne im Prinzip eine Version hätte, wo ich statt dem GUI z. B. eine Klasse mit einer HTML-Präsentation (HTML-Seite bauen oder nur aufrufen) hätte.

Mal etwas Pseudocode:

Code: Alles auswählen

from bibliothek1 import Klasse
from bibliothek2 import GUI

if __name__ == "__main__":
    
    tool = Klasse()
    app = QtGui.QApplication(sys.argv) 
    dialog = MeinDialog()
    tool.aktualisieren()
    tool.warte()
    dialog.show()
    tool.aktualisieren()
    tool.berechnen()
    dialog.label1.setText("In Arbeit!")
    sys.exit(app.exec_())
Kann ich mir das so in etwa vorstellen oder ist das schwierig? Kann ich die Sprechblase direkt aus der Programmierlogik meines Skripts aufrufen und ändern oder muss ich beides miteinander verbinden, d. h. letztlich eine Qt-App schreiben. Muss ich das in threads packen und nach welchen Begriffen müsste ich dann googlen, um mich zu informieren, wie die miteinander interagieren.

An der Stelle stehe ich auf dem Schlauch.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

pixewakb hat geschrieben: Kann ich mir das so in etwa vorstellen oder ist das schwierig?
Nein und nein!

Die Aufrufe ``tools.some_method()`` müssen natürlich *in* der entsprechenden UI-Komponente erfolgen.

Einfaches Beispiel: Du hast einen "Berechne"-Knopf. Das GUI-Framework kennt nun eine Art Event-Handling, welches beim Druck auf den Button in eine definierbare Methode / Funktion / Callable springt. In diesem muss dann so ein Aufruf a la ``tools.berechnen()`` stehen, der die eigentliche Arbeit ausführt.

Willst Du das ganze in eine Web-Applikation integrieren, so ändert sich alles "drum herum", aber der Aufruf ``tools.berechnen()`` wird auch dort irgend wo in einer Handler-Funktion stehen, die aufgrund einer Client-seitigen Benutzeraktion aufgerufen wird.

Ergo: *Wie*, *wo* und *wieso* Methoden Deiner Domänen-Libs aufgerufen werden, ändert sich natürlich abhängig von der jeweiligen Präsentationsschicht (Web, GUI, CLI, ...) bzw. dem dafür verwendeten Rahmenwerk.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
pixewakb
User
Beiträge: 1413
Registriert: Sonntag 24. April 2011, 19:43

@Hyperion, danke, das hatte ich befürchtet. Das war das, wie ich es von PyQt aus dem letzten oder vorletzten Jahr noch kannte.

Im Grunde habe ich aktuell ein Skript, was durch den Windows-Autostart gestartet wird und dann alle halbe Stunde (time.sleep(60 * 30)) prüft, ob ein Zeitpunkt t1 erreicht ist und dann Aktionen durchführt, um anschließend wieder in einen Wartemodus zu verfallen bis ein Zeitpunkt t2 eingetreten ist, um dann erneut die Arbeit zu beginnen.

Ich hatte im Kern überlegt und das ist meine Frage, ob es eine Möglichkeit gibt, dass diese "Routine" das GUI startet und von sich aus Daten ändert, d. h. nicht auf Benutzeraktionen reagiert, sondern von sich aus agiert und interagiert (etwa so wie bei einem Antivirenprogramm, das zeitgesteuert startet, ein GUI zeigt und Arbeiten erledigt).

Fragen: (1) Ich sehe es richtig, dass ich dann eine Qt-App schreiben muss? (2) Diese Funktion (schlafe x Sekunden) müsste ich demnach mittels Qt-eigenen Methoden umsetzen, die ich wohl dann in der init-Methode parke (um so etwas zu erreichen wie beim Antivirenprogramm)?

Zu meinem Tool: Möglicherweise arbeite ich anders und packe ein PHP-Skript rein, das mittels webbrowser.opennewtab(...php) geöffnet wird und das erledigt, was ich brauche (Warnung des Benutzers = ich, bitte nicht den Rechner runterzufahren). Aktuell will ich bestimmte Aufgaben automatisieren, es gibt meinerseits nicht zwingend eine Präferenz zu einem GUI, wenn nur die Arbeit erledigt wird. GUI wäre aber auch mal wieder schön.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Man kann solche "TrayIcon"-Appikationen sicherlich auch mit anderen GUI-Frameworks hinbekommen, aber mit Qt geht das auf jeden Fall auch - und iirc auch recht einfach :-)

Du brauchst sicherlich einen Mechanismus, der irgend wie asynchron mit einer Qt-Komponente interagiert, aber ob Du das Threading komplett im Qt-Teil erledigst, musst Du entscheiden. Sollte das ein Kernbestandteil Deiner Applikation sein, so würde ich das ja auch in die Library integrieren (natürlich ohne Qt!).

Natürlich kannst Du auch einen Dienst schreiben (k.A. ob das in Python direkt geht, oder man einen Wrapper benötigt!), der dann zu gegebener Zeit eine GUI startet. Aber wie BlackJack schon sagte, nervt so etwas den Benutzer in den allermeisten Fällen ;-)

Evtl. gibt es für Windows 8.x sogar noch ganz andere Optionen (Kachel-Zeugs!)

Das mit dem PHP habe ich nicht kapiert - PHP ist ja etwas serverseitiges; wie willst Du das lokal ausführen? Dazu bräuchte es ja einen Webserver mit PHP-Integration... klingt für mich nach viel zu viel Overhead für dieses Benachichtigungsproblem :-)

Evtl. meinst Du aber auch nur "HTML" - das kannst Du natürlich auch lokal in einem Browser aufrufen. Aber auch das klingt für mich eher suboptimal. Der Systemtray ist doch eigentlich genau für solche im Hintergrund arbeitenden Programme gemacht; das würde ich nutzen :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@pixewakb: Letztendlich musst Du eine Qt-Anwendung schreiben wenn Du Qt für die Anzeige, wo auch immer, verwenden möchtest. Die Frage ob das warten in Deinem Werkzeug passiert oder auch von aussen passieren kann, ist doch eigentlich nicht so wirklich wichtig. Wenn das warten im Werkzeug selbst passiert, musst Du halt einen geeigneten Mechanismus bereitstellen um anderen Code darüber informieren zu können das etwas bestimmtes passiert, zum Beispiel das staren und beenden von Berechnungen und eventuell noch Statusinformationen während der Berechnung. Das kommt halt darauf an was Du da machen willst.

Wenn es parallel zur GUI laufen soll, dann brauchst Du mindestens Threads solange die Berechnungen nicht nur sehr kurz laufen. Man könnte die Anzeige und die Berechnung auch in verschiedenen Prozessen laufen lassen, die zum Beispiel über Sockets kommunizieren.

Zwischen einer GUI und einer Webseite ist auf jeden Fall schon mal der Unterschied das man bei einer GUI die Informationen ”pushen” wird, HTTP aber per ”pull” funktioniert. Also bei einer GUI schreibst Du Code der sagt, zeige jetzt dies an, während man bei einer Webanwendung Code schreibt der darauf wartet das jemand eine aktualisierte Darstellung abfragt. GUIs kann man auch so schreiben, Webanwendung eher nicht anders, zumindest nicht so universell, browserübergreifend.

Du wirst bei Deinem Werkzeug ganz einfach die Berechnung von der Datenein-/ausgabe sauber trennen müssen. Sämtliche Ereignisse und Ausgaben müssen über Rückrufmechanismen abfragbar sein. Dann kann man das ohne Abhängigkeiten zu Qt umsetzen. Für die GUI schreibt man dann einen Adapter als Qt-Objekt der sich für alle Ereignisse registriert die man in der GUI irgendwie darstellen möchte, und die in Signale umwandelt damit sie vom Werkzeug-Thread in den GUI-Thread gelangen können, wo sie dann in Slots in enstrechende Aktionen in der GUI umgesetzt werden.
Antworten