Klasse innerhalb einer GUI aufraufen/verwenden

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
MtiQS
User
Beiträge: 4
Registriert: Dienstag 25. Mai 2010, 09:55

Hallo,

ich bin absoluter Newbie in der Python-Programmierung und benötige etwas Hilfe.

Hier mal eine kurze Beschreibung meines Problems:

Ich habe ein Programm(nicht Python) welches mir Daten zur Verfügung stellt. Mit Hilfe einer Exportfunktion kann ich diese einem beliebigen Python-Script zur Verfügung stellen. Dies geschieht in einer Klasse mit folgendem Aufbau:

Code: Alles auswählen

class Test:
    def __init__(self, AString='' ):
        self.AString = ''
    
    def OnTest(self):
        print 'Test: ' + self.AString 
Das klappt soweit auch ganz gut. Jedesmal wenn ein neuer Wert im Programm eintrifft wird im Python-Script die Funktion "OnTest()" aufgerufen und der Wert ausgegeben.

Nun möchte ich aber die eintreffenden Daten im Pythonscript grafisch darstellen, z.Bsp. in einem Chartdiagramm. Dazu gibt es ja Komponenten wie "matplotlib" o.ä.
Wie packe ich das alles nun in ein GUI, z.B. mit Tkinter, und die Ausgabe erfolgt nicht als print sondern in einem Memo oder Label?

Vielen Dank schon mal im Voraus!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Indem du die entsprechenden Ausgabemoeglichkeiten des GUI-Toolkits nutzt, also statt `print` `label.setText` oder aehnliches benutzt. Das ist aber sehr abhaenging vom Toolkit, und keine generelle Frage wie du es formulierst.

Wenn du also das verwendete Toolkit benennst kann man dir besser helfen.

P.S. Du solltest dir mal PEP 8 anschaun.
MtiQS
User
Beiträge: 4
Registriert: Dienstag 25. Mai 2010, 09:55

Ich denke, ich muss mal etwas weiter ausholen.

Das Python-Script wird immer als Gast innerhalb eines Host-Systems ausgeführt. Das Host-System ist ein Delphi-Programm, welches die Daten zur Verfügung stellt, auf die im Script zugegriffen werden soll/kann. Dazu stellt das Host-System eine IDE zur Verfügung mit deren Hilfe der Anwender beliebigen Python-Code innerhalb des Hosts ausführen kann. Dabei hat der Anwender die freie Wahl, ob das Script im Hintergrund oder mit GUI läuft.
Momentan habe ich ein Beispiel-Script, in dem alle zur Verfügung stehenden Werte des Host-Systems in Klassen gekapselt sind. Jede Klasse hat eine Funktion, vergleichbar mit einem Event, die vom Host ausgelöst wird, wenn sich der zugehörige Wert ändert. So kann man innerhalb dieser Klassenfunktion den Wert verwenden und weiter verarbeiten.

Hintergrund des Ganzen ist es, dem Anwender die Möglichkeit zu geben eigene Scripte/Programme zuschreiben, mit Allem was Python zur Verfügung stellt und dabei die vom Host bereitgestellten Werte zu nutzen.

Beispiel:

Das Host-System stellt Echtzeit-Börsendaten zur Verfügung. Die Pythonklasse dazu ist wie folgt definiert:

Code: Alles auswählen

class RT:
    def __init__(self, Symbol='', Ask_TimeStamp='', Ask_Price='', Ask_Volume='', Bid_TimeStamp='', Bid_Price='', Bid_Volume='' ):
        self.Symbol = ''        
        self.Ask_TimeStamp = '' 
        self.Ask_Price = ''     
        self.Ask_Volume = ''    
        self.Bid_TimeStamp = ''
        self.Bid_Price = ''     
        self.Bid_Volume = ''  
  
    def OnRT(self):
        print self.Symbol
        
        """ Place your code for RT calculations here """
    # end OnRT()
# end class RT
Die Funktion OnRT() wird vom Host-System immer dann aufgerufen wenn ein neure Kurswert vorliegt. Alle Properties werden mit den entsprechenden Werten vom Host befüllt und stehen im Python-Script zur Vefügung. Innerhalb des OnRT() kann der Anwender jetzt die Daten weiterverarbeiten, also bspw. in eine Datei schreiben, per TCP/IP weiterleiten, Berechnungen anstellen, in einen Chart plotten oder was auch immer mit Python möglich ist.
Für den Fall das der Anwender sich entscheidet ein Programm mit GUI zu verwenden soll er dies auch tun können, egal welches Framework/Toolkit er vorzieht.

Ich wollte es der Einfachheit halber an einem kleinen Beispiel mit Tkinter machen.

Wenn ich es recht verstehe läuft unter Python eine GUI-Anwendung, hier am Beispiel Tkinter, innerhalb der Befehle

Code: Alles auswählen

from Tkinter import *
root = Tk()
l = Label( root, text='bla bla bla' )
l.pack()

# weiterer Code

mainloop()

Wenn ich z.B. das Label updaten möchte, dann kann ich ja etwas in der Form wie:

Code: Alles auswählen

while True:
    time.sleep(0.5)
    l[ "text" ]='anders bla bla bla'
    root.update()
vor mainloop() an der Stelle '# weiterer Code' einfügen und das Label würde alle 0,5 Sekunden geupdatet. Oder?

Nun wäre meine Frage an die Python-Freaks:

Wo und wie muss ich meine Klasse innerhalb des o.g. GUI-Beispieles einfügen das z.B. das Label mit Werten aus der OnRT() Funktion befüllt würde. Geht das direkt oder über eine globale Zwischenvariable?

Danke schon mal im Voraus.
BlackJack

@MtiQS: In Deiner ``while``-Schleife ersetzt Du ja die `mainloop()`. So arbeitet man normalerweise nicht mit GUIs. Das ist alles ein wenig komplizierter.

Wie machst Du der Host-Anwendung Deine Klassen denn bekannt? Kannst Du davon unabhängig vor dem ersten Aufruf der `On*()`-Methode Python-Code ausführen? Zum Beispiel um die GUI zu initialisieren?

Da man auf GUIs in der Regel nicht aus verschiedenen Threads zugreifen darf, müsstest Du bei Tkinter wahrscheinlich eine "Schleife" mit der `after()`-Methode (die gibt's auf jedem Widget) basteln, die regelmässig zum Beispiel in einer `Queue.Queue` nachsieht, ob neue Daten anzuzeigen sind, und in Deiner `On*()`-Methode kannst Du die Daten in die Queue stecken. Diese Queue wäre dann der Kommunikationskanal zwischen dem Thread in dem die Hostanwendung läuft und dem, wo die `mainloop()` der GUI läuft.
MtiQS
User
Beiträge: 4
Registriert: Dienstag 25. Mai 2010, 09:55

Kannst Du davon unabhängig vor dem ersten Aufruf der `On*()`-Methode Python-Code ausführen? Zum Beispiel um die GUI zu initialisieren?
Aus Sicht des Hosts (Delphi) läuft es so:

Ich habe hier eine Python-Engine in die ich ein Script mit Klassendefinitionen reinlade, z.B. sowas:

Code: Alles auswählen

# UTC
class UTC:
    def __init__(self, UTCDateTime='', LocaleDateTime='' ):
        self.UTCDateTime = ''
        self.LocaleDateTime = ''
    
    def OnUTC(self):
        print 'UTC: ' + self.UTCDateTime
        
        """ Place your code for date/time related operations here """
  # end OnUTC()
Diese Klasse übergibt per OnUTC()-Event zwei Timestamps an das Script.

Der Aufruf innerhalb des Hosts erfolgt in einem Timerevent (jede Sekunde) und sieht so aus:

Code: Alles auswählen

private
{ Private declarations }
    // Wrapper classes
    UTC4Py                  : Variant;
    ......

procedure TFrmScripting.Set_UTC_Python;  // wird jede Sekunde von einem Timer aufgerufen
begin
  self.UTC4Py.UTCDateTime     := DateTimeToStr(core.FrmCore._Global.UTC.UTCDateTime);
  self.UTC4Py.LocaleDateTime  := DateTimeToStr(core.FrmCore._Global.UTC.LocaleDateTime);
  self.UTC4Py.OnUTC();
end;
Solange das Script in der Engine geladen ist wird jedesmal bei der Zuweisung von "self.UTC4Py.OnUTC();" die entsprechende Funktion "def OnUTC(self):" auf Pythonseite angesprochen und ausgeführt.

UTC4Py ist aus Delphisicht eine Varaible vom Type Variant, der ich die Properties UTCDateTime und LocaleDateTime zuweise plus der Funktion OnUTC()

Ich kann im Pythonscript natürlich vor den Klassendefinitionen noch anderen Code platzieren um die GUI zu initialisieren.
BlackJack

@MtiQS: Warum hat die `__init__()` eigentlich Argumente? Die werden ja nie verwendet.
MtiQS
User
Beiträge: 4
Registriert: Dienstag 25. Mai 2010, 09:55

Das habe ich aus einem Beispiel so übernommen und habe noch nicht geprüft ob es notwendig ist. Kann man sicherlich auch weglassen.

Mehr zur Funktion der Kommunikation Delphi <--> Python gibt es unter http://www.atug.com/andypatterns/pythonDelphiTalk.htm

Eventuell kann man ja meine Python-Klasse "UTC" innerhalb der GUI als Member der obersten GUI-Klasse definieren, falls es sowas gibt in Python.
Antworten