Jump to content

[Python] grafische Oberfläche für Anfänger


Recommended Posts

Ich bin ein ziemlicher Python-Neuling und versuche mich jetzt mit Tkinter, weil es mir scheint, dass eine grafische Oberfläche mit Buttons deutlich weniger Code braucht als eine simple Tastendruck-Abfrage per Konsole.

 

Leider habe ich mich im Dschungel der Objekte, Klassen und Instanzen verirrt. Insbesondere ist mir schleierhaft, was man in welcher Reihenfolge definieren bzw. programmieren muss.

 

Als erster Gehversuch soll ein IO4-Eingang den Text eines Labels verändern, aber ich schaffe es nicht. Hier mal ein ganz grober Ablauf:

 

from Tkinter import *
...
UID_IO4 = "7Qo"          # IO-4 Bricklet
io4 = IO4(UID_IO4)       # Create device object
ipcon = IPConnection(HOST, PORT)        # Create IP conn. to brick
ipcon.add_device(io4)                   # Add device to IP conn.

# Callback function for interrupts 
# Ja, etwas blöd so mitten drin, aber das gab die wenigesten Fehler
def cb_interrupt(interrupt_mask, value_mask):
    if ((interrupt_mask == 4) & ((value_mask & 4) == 0)):
        print "EIN"                 # das funktioniert noch!
        App.anschlo("EIN")          # das ist fehlerhaft

# Enable interrupt  
io4.set_interrupt((1 << 2)|(1 << 3))
# Register callback for interrupts
io4.register_callback(io4.CALLBACK_INTERRUPT, cb_interrupt)

class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.anschl1 = Label(frame, text="x")
        self.anschl1.pack(side=LEFT)

        self.button = Button(frame, text="QUIT", command=self.ende)
        self.button.pack(side=LEFT)

    def anschlo(tx):
        self.anschl1.text = tx

    def ende(self):
        ipcon.destroy()
        print "IP destroyed."
        root.destroy()

root = Tk()
app = App(root)
root.mainloop()

Die Interrupt-Routine scheint das Label nicht zu kennen oder falsch anzusprechen oder...

Ich würde mich freuen, wenn jemand dieses Programm ein wenig aufräumen würde.

Link to comment
Share on other sites

Deine def vom anschlo ist kaputt:

def anschlo(tx):

 

richtig wäre

def anschlo(self, tx):

 

Ich bin auch nie drauf klargekommen, dass man in python das self explizit als ersten Parameter mit übergibt ^^ Also das ist mira uch oft passiert :D

 

P.S.: Ah okay, das war nur die Halbe Lösung ^^

Oben im Callback nutzt du ja App (großgeschrieben), das wäre dann vermutlich ein statischer Aufruf (bin mir unsicher), bei dem gäbe es aber kein self.

 

Ich entwirr das ganze mal noch kurz in meinem Kopf und dann poste ich hier drunter neuen Code ^^

 

from Tkinter import *

# ich habe mal zur Entwirrung alles sortiert (globals ganz oben, dann defs, dann class, dann main-code)
# wenn das nen Unterschied macht muss es irgendwann zu Irritation kommen 
# lieber rechtzeitig vorbeugen 

app = None # der aktuelle Code braucht das als global (muss man in Python doch vorher definieren oder?)

def cb_interrupt(interrupt_mask, value_mask):
    if ((interrupt_mask == 4) & ((value_mask & 4) == 0)):
        print "EIN"                 # das funktioniert noch!
        app.anschlo("EIN")          # das sollte jetzt hoffentlich auch gehen

class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.anschl1 = Label(frame, text="x")
        self.anschl1.pack(side=LEFT)

        self.button = Button(frame, text="QUIT", command=self.ende)
        self.button.pack(side=LEFT)

    def anschlo(self, tx):
        self.anschl1.text = tx

    def ende(self):
        ipcon.destroy()
        print "IP destroyed."
        root.destroy()

UID_IO4 = "7Qo"          # IO-4 Bricklet
io4 = IO4(UID_IO4)       # Create device object
ipcon = IPConnection(HOST, PORT)        # Create IP conn. to brick
ipcon.add_device(io4)                   # Add device to IP conn.

root = Tk()
app = App(root)
root.mainloop()

# callback erst dann registrieren, wenn die Variable "app" auch gesetzt ist
# sonst würde die "cb_interrupt" methode explodieren (viel Rauch und Schutt)
io4.set_interrupt((1 << 2)|(1 << 3))
io4.register_callback(io4.CALLBACK_INTERRUPT, cb_interrupt)

 

Dieser Code ist bei mir gerade rausgekommen und sollte laufen... hoffe ich ^^

DAs Problem ist, dass ich gar nicht so gut bin in Python. Normalerweise hätte ich dir auch dazu geraten, dass du die cb_interrupt-methode in deine App-Klasse hineinziehst, aber ich glaube nicht, dass das geht, weil ja der explizite self-parameter stören würde. In anderen Sprachen ginge das tatsächlich, hier hab ich gerade keine hübsche Idee. Deswegen auch app als globale Variable (nicht soooo toller Stil).

 

Hoffe ich konnte helfen.

Link to comment
Share on other sites

Herzlichen Dank erst mal, ich werde das heute abend ausprobieren.

 

Mir ist das alles ein Rätsel (von wegen "Python ist soooo einfach"), insbesondere denke ich, root.mainloop() soll m.W. eine Endlosschleife sein, in der das Programm quasi "gefangen" ist und nur noch auf Ereignisse (Interrupts) warten kann... wie zum Geier kann danach noch weiterer Code stehen und ausgeführt werden?

Link to comment
Share on other sites

Das liegt daran, dass ich eben ein Dummkopf bin :D

 

Also wenn das ne Endlosschleife ist dann sollte der Code natürlich nochd avor sein. Aber auch NACHDEM app definiert wurde.

 

Also genau zwischen diesen beiden Zeilen:

app = App(root)
root.mainloop()

 

War mein Fehler ^^

Link to comment
Share on other sites

Das liegt daran, dass ich eben ein Dummkopf bin :D

 

Also wenn das ne Endlosschleife ist dann sollte der Code natürlich nochd avor sein. Aber auch NACHDEM app definiert wurde.

Ich weiß nicht, ob das eine Endlosschleife ist, aber in dem Tutorial, wo ich das her habe, stand das so drin. Und der Rest ist bloß gesunder Menschenverstand.

 

Aber jetzt wo du's sagst... in dem Beispiel von Tinkerforge gibt es keine Endlosschleife... das verstehe wer will...

Link to comment
Share on other sites

Ja Python ist programmier technisch für Einsteiger gut aber ich glaube, wenn man GUI programmieren möchte gibt es besseres.  8)

 

Wem sagt du das. Meine Lieblingssprache ist immer noch der BASIC-Dialekt "Rapid-Q", zwar veraltet und ungepflegt, läuft aber auch unter Win7, was will man mehr. Rapid-Q ist super für kleine Projekte, weil man die Form mit allen Elementen sowie den Programmcode in eine einzige Datei packen kann.

 

Es ist nur nicht so extrem objektorientiert, und man kann wahrscheinlich keine Callbacks programmieren, aber mir würde das genügen, alles in einer einzigen Endlosschleife abzufragen.

 

Ich bräuchte nur eine dafür geeignete DLL, dann wäre Python für mich gestorben.

Link to comment
Share on other sites

Sagen wir es so: GUI-Programmierung ist immer ziemlich übel, weil du neben der Programmiersprache auch gleich noch mittelgroße Frameworks und deren Konzepte mitverstehen musst. Allerdings gibt es auch schlanke GUIs, aber meist ist das nen Stück mehr Aufwand als ne Konsolenanwendung.

 

@Plenz: was war der Grund warum du nicht einfach ne Konsolenanwendung gemacht hast? Du hattest am Anfang angedeutet, dass dir ne GUI leichter schien als ne Konsole

Link to comment
Share on other sites

@Plenz: was war der Grund warum du nicht einfach ne Konsolenanwendung gemacht hast? Du hattest am Anfang angedeutet, dass dir ne GUI leichter schien als ne Konsole

Hatte ich oben schon erwähnt: es geht um die simpele Abfrage von Tasten. Einfach eine Schleife, in der pausenlos der Tastaturpuffer abgefragt wird, und wenn das "A" gedrückt wird, dann tu dies, und wenn "B" gedrückt wird, dann tu das. Ich habe mich dumm und dusselig gesucht nach so einem Code, aber nichts gefunden. Dagegen war das Beispiel für eine winzige Form mit einem Button, der per Klick eine Subroutine startet, völlig simpel und kurz.

 

Das Problem war nur, die zwei Beispiele zusammenzubasteln. Dein Code ist schon fast perfekt, nur zwei Sachen habe ich jetzt herausgefunden: die Zeile "app = None" ist überflüssig, und ein Label textet man um mit label.config(text="abcde")

 

Jedenfalls danke für deine Hilfe.

Link to comment
Share on other sites

Also wenn ich mir das bei Netbeans angucke ist das ziemlich einfach eine GUI zu basteln.

Mit Rapid-Q sieht das so aus:

DECLARE SUB Geklickt

CREATE MYFORM AS QFORM
  CREATE MyLabel AS QLABEL
    Caption = "vorher"
  END CREATE
  CREATE MyButton AS QBUTTON
    Caption = "Klick mich!"
    OnClick = Geklickt
  END CREATE
END CREATE

SUB Geklickt
  MyLabel.Caption = "nachher"
END SUB

Ist wohl selbsterklärend  ;)

Link to comment
Share on other sites

die Zeile "app = None" ist überflüssig

 

Oh cool, dann war Python doch besser als ich in Erinnerung hatte :D hatte befürchtet die Deklaration müsste im Code "vorher" erfolgen.

 

Wegen Rapid-Q: Sieht auf jeden Fall schön simpel aus ^^ Und Offensichtlich werden ja sogar Delegates unterstützt ;) (OnClick = Geklickt)

 

Ich befürchte allerdings, dass es so schnell keine Rapid-Q Bindings geben wird ^^ Zumindest habe ich in diesem Thread das erste Mal davon gehört...

Link to comment
Share on other sites

Wegen Rapid-Q: Sieht auf jeden Fall schön simpel aus ^^ Und Offensichtlich werden ja sogar Delegates unterstützt ;) (OnClick = Geklickt)

 

Ich befürchte allerdings, dass es so schnell keine Rapid-Q Bindings geben wird ^^ Zumindest habe ich in diesem Thread das erste Mal davon gehört...

Delegates? Nie gehört. Für mich sind das Ereignisse.

 

Rapid-Q-Bindings müssen gar nicht sein, man bräuchte einfach nur eine DLL, die nicht so objektorientiert angesprochen werden muss wie die Tinkerforce.dll. Ich muss allerdings zugeben: auf Callbacks müsste man vermutlich verzichten.

Link to comment
Share on other sites

Also wenn ich mir das bei Netbeans angucke ist das ziemlich einfach eine GUI zu basteln. Bei Bedarf mach ich n Video bzw suche eins raus

 

ich hätte großes Interesse an dem Video...

Wäre toll, wenn du das machen würdest. Vielleicht kannst du das ja in Kombination mit einem TF-Produkt machen, dann könnten wird das vllt sogar in der Wiki verlinken.

Kann ja was ganz einfaches sein. Programm zum Beschreiben des LCDs oder "bei Buttonklick lese Temperatur aus" oder sowas.

 

Link to comment
Share on other sites

ich hätte großes Interesse an dem Video...

Ich hasse Video-Tutorials. Viel besser ist ein geschriebenes Dokument mit Screenshots, das braucht man nicht zu stoppen und weiterlaufen zu lassen, und interessante Zeilen kann man per Copy und Paste gleich weiterbenutzen.

 

 

Link to comment
Share on other sites

Delegates? Nie gehört. Für mich sind das Ereignisse.

 

Keine Ahnung wie das in Rapid-Q genannt wird, aber es sieht zumindest aus als könnte man über diese Ereignisse Callbacks abbilden. Mehr wollte ich gar nciht sagen ^^

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...