GUI in Programm integrieren

Fragen zu Tkinter.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

GUI in Programm integrieren

Beitragvon klaus » Freitag 21. September 2007, 20:08

Hi,

Ich hab ein Problem mit Tkinter. Ich weiß nicht wie ich es hinkriegen soll, diese Funktion

Code: Alles auswählen

def frage(data):
    question, solve, stat = data
    solution = solve.split(", ")
    answer = raw_input(question)
    if answer in solution:
        print "Richtig!"
        data[2] = data[2] + 2
        return 1
    else:
        print "Falsch! Richtig ist: ", solve
        data[2] = data[2] + 1
        return 0


und diese Klasse:

Code: Alles auswählen

class Iface:
    def __init__(self, master):       
        frame = Frame(master, width=300, height=200)
        frame.pack()
        self.label = Label(frame, text="Start", pady=10)
        self.label.pack()
        self.entry = Entry(frame)
        self.entry.bind("<Return>", self.get_entry)
        self.entry.pack()
        self.solve=Button(frame, text="Start")
        self.solve.pack()

    def get_entry(self, event):
        x = self.entry.get()
        return x


miteinander zu kombinieren.
Dabei soll dann:
1. "question" dem Label als Text zugewiesen werden.

2. Der Benutzer gibt dann seine Antwort ind das Feld ein und drückt Enter, wodurch die Funktion entry_get() seine Eingabe zurückgibt. Diese soll dann answer zugewiesen werden.

3. Dann soll dem Button entweder "Richtig!" bzw. "Falsch ..." zugewiesen werden. Wenn der Benutzer auf den button klickt, bzw. nochmal Enter drückt soll die nächste Frage gestellt werden.

Es würde mich freuen, wenn mir jemand helfen könnte. Ich hab bis jetzt noch keine Erfahrungen mit Tkinter und weiß daher überhaupt nicht, wie ich das umsetzen soll.
BlackJack

Beitragvon BlackJack » Freitag 21. September 2007, 20:33

Die beiden Quelltextfragmente wirst Du nicht kombinieren können. Es sind beides "GUI"s für unterschiedliche "Toolkits". Eine "GUI" ist eben eine Textoberfläche.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Beitragvon poker » Freitag 21. September 2007, 20:46

Stimmt, er könnte aber die Funktionalität von ``frage()`` in ``Iface`` einbinden. Also das ``raw_input`` und die ganzen print's loswerden.
Kurz: Ein rewrite.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Samstag 22. September 2007, 19:45

Auch damit hätte ich kein Problem, hauptsache ich schaff es, das ich durch irgendeinen Befehl (vorzugsweise Funktionsaufruf) den gewünschten Effekt erziele und das Programm das macht, was es soll, nämlich aus der Liste ["Frage", "Antwort", 0] die richtige Anzeige.

Ich kann ja mal versuchen, die Funktion irgedwie in die Klasse zu integrieren, allerdings hab ich dann immernoch das Problem, wie ich der Klasse sagen soll, dass sie ne Frage stellen soll.

Es wäre allerdings nett, wenn irgendjemand mal nen Lösungsansatz posten könnte, weil ich hab nämlich bis jetzt keine Ahnung, wie ich das umsetzen soll und ich wollte eigentlich bis zum Schuljahresende fertig sein (Ab da hab ich dann nämlich voraussichtlich kein Latein mehr :wink: ).
BlackJack

Beitragvon BlackJack » Samstag 22. September 2007, 20:07

Du musst wohl etwas umdenken müssen. GUIs sind in der Regel ereignisbasiert, d.h. Du rufst keine Funktion auf die alles steuert, sondern du baust die GUI auf und reagierst auf entsprechende Ereignisse. Also zum Beispiel das ein Button gedrückt wurde.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Samstag 22. September 2007, 20:35

Dann muss ich einen Weg finden (falls es einen geben sollte), wie ich es schaffe, in dem Programm ein Ereignis zu erzeugen, auf welches dei GUI dann reagiert.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Beitragvon poker » Samstag 22. September 2007, 21:00

klaus hat geschrieben:Dann muss ich einen Weg finden (falls es einen geben sollte), wie ich es schaffe, in dem Programm ein Ereignis zu erzeugen, auf welches dei GUI dann reagiert.
Vorausgesetzt du hast die tuts durchgearbeitet, ist das doch relativ simpel.

Du baust dir eine GUI in dem du eine Eingabezeile. Bei jedem eintragen der Antwort erzeugt das ``Eingabezeile``-Widget ein Event. Danach schreibst du eine Methode (Event-Handler) die an das Event gebindet wird. Immer wenn dann das Event ausgelöst wurde, wird dann diese Methode gestartet in den dann dein Code ausgeführt wird.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Sonntag 23. September 2007, 15:51

Ich bin jetzt schon mal so weit gekommen:

Code: Alles auswählen

from Tkinter import *

data = ["abc", "a, b, c", 0]
question, solve, stat = data
solution = solve.split(", ")

class Iface:
    def __init__(self, master):
        frame = Frame(master, width=300, height=200)
        frame.pack()
        self.label = Label(frame, text=question, pady=10)
        self.label.pack()
        self.entry = Entry(frame)
        self.entry.bind("<Return>", self.correct)
        self.entry.pack()
        self.solve=Button(frame, text="-------")
        self.solve.bind("<1>", self.next)
        self.solve.pack()

    def correct(self, event):
        x = self.entry.get()
        print x
        if x in solution:
            respond = "Richtig!"
        else:
            respond = "Falsch! Richtig ist "+ solve
        self.solve.config(text=respond)

    def next(self, event):
        pass

root=Tk()
iface=Iface(root)
root.mainloop()


Ich muss es jetzt nur noch hinkriegen, mit next() die nächste Frage aufzurufen, und des ganze überhaupt erstmal zu starten.
BlackJack

Beitragvon BlackJack » Sonntag 23. September 2007, 17:30

Aktionen für Buttons gibt man in der Regel als `command`-Argument beim Erzeugen des Buttons an. Wenn Du die Maustaste an den Button bindest, verhält sich das ganze nicht so, wie man das von Buttons sonst gewohnt ist.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Montag 24. September 2007, 14:43

Wenn ich das mache, ist in der Funktion next die Variable self nicht bekannt. Ich habs nicht geschafft des zu umgehen.
Ich hab jetzt mal wieder ein paar Sachen in Angriff genommen, z.B. dass das Programm nicht mehr reagiert, wenn man 2 Mal hintereinander auf Enter bzw. den Button klickt. Dafür hab ich allerdings ein paar globale Variablen in Kauf nehmen müssen, was ich nicht so toll finde. Ich bin für jeden Verbesserungsvorschlag offen. Hier ist mal Code:

Code: Alles auswählen

from Tkinter import *

index = [["1", "2", 0], ["2", "3", 0], ["3", "5", 0], ["4", "7", 0]]
counter, switch = 0, 0

class Iface:
    def __init__(self, master):
        global solve
        question, solve, stat = index[0]

        frame = Frame(master, width=300, height=200)
        frame.pack()
        self.label = Label(frame, text=question, pady=10)
        self.label.pack()
        self.entry = Entry(frame)
        self.entry.bind("<Return>", self.correct)
        self.entry.pack()
        self.button=Button(frame, text="-------")
        self.button.bind("<1>", self.next)
        self.button.pack()

    def correct(self, event):
        global switch, counter
        if switch:
            pass
        else:
            counter = counter + 1
            x = self.entry.get()
            if x in solve.split(", "):
                respond = "Richtig!"
            else:
                respond = "Falsch! Richtig ist "+ solve
            self.button.config(text=respond)
            switch = 1 - switch
       
    def next(self, event):
        global switch, question, solve, stat
        if not switch:
            pass
        else:
            print "Button pressed"
            question, solve, stat = index[counter]
            self.label.config(text=question)
            self.entry.config(text="")
            self.button.config(text="-------")
            switch = 1 - switch
       

root=Tk()
iface=Iface(root)
root.mainloop()


Ich würde allerdings noch gerne wissen, ob man ein Entry-Feld reseten kann, damit es wieder leer wird. Ich habe das schon mit
self.entry.config(text="")
probiert, aber es hat nicht geklappt.

Außerdem, wieso funktionieren width und height im Frame (Z 11) nicht?
BlackJack

Beitragvon BlackJack » Montag 24. September 2007, 15:04

Das kann nicht sein das `self` nicht bekannt ist, das ist das erste Argument von `next()`.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Montag 24. September 2007, 18:54

Ja, wenn ich next() über .bind aufruf. Wenn ich es über command aufruf (wie du es vorgeschlagen hast) wird ihm nur das Event als Argument übergeben, aber nicht self.
Es wird ja dann mit command = next aufgerufen (nicht mit self.next).
Die Parameter lauten dann next(event) und nicht next(self, event).
Deswegen muss ich auch mit "<1>" arbeiten. Allerdings weicht das Verhalten gegenüber einem "gewöhnlich" erstellten Button mit command nur sehr gefingfügig ab, was ich wahrscheinlich in Kauf nehmen muss.

Ich bin aber für jede bessere Lösung offen, und wäre froh, wenn mir jemand einen Tipp geben könnte, wie ich index (die Vokabelliste) jetzt noch durch den Benutzer einstellen lassen kann, bevor die Abfrage startet. Bis hierher hab ich mich nämlich schon mehr schlecht als recht durchgewurschtel, und da Tkinter für mich absolutes Neuland ist, gehen mir allmählich die Umsetzungsideen aus.
Zuletzt geändert von klaus am Montag 24. September 2007, 19:05, insgesamt 1-mal geändert.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Beitragvon poker » Montag 24. September 2007, 19:03

klaus hat geschrieben:
Die Parameter lauten dann next(event) und nicht next(self, event).
Hi versuch es doch mit einem lambda:

Code: Alles auswählen

self.button.bind("<1>", lambda event: self.next(self, event))

Sollte funktionieren.
Benutzeravatar
klaus
User
Beiträge: 88
Registriert: Samstag 23. Juni 2007, 09:33
Wohnort: Kaufbeuren
Kontaktdaten:

Beitragvon klaus » Montag 24. September 2007, 19:07

@ poker: bei .bind klappt es doch. Nur BlackJack hat gesagt, ich soll es mit command umsetzen und da hat die Funktion kein Parameter self. Außerdem weiß ich nicht mal im Ansatz, was lambda bewirkt.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Beitragvon poker » Montag 24. September 2007, 19:24

klaus hat geschrieben:@ poker: bei .bind klappt es doch. Nur BlackJack hat gesagt, ich soll es mit command umsetzen und da hat die Funktion kein Parameter self. Außerdem weiß ich nicht mal im Ansatz, was lambda bewirkt.
Argh sorry, hab das ganze falsch verstanden.

Labmbda macht eine anonyme Funktion. ``f = lambda x: x`` macht das gleiche wie ``def f(x): return x`` mit dem unterschied das man lambda auch in ausdrücken lokal definieren kann, halt anonym. Damit kann man dann z.B. dirket in einem Funktionsaufruf, der als Parameter eine Funktion erwartet, eine Funktion definieren was mit ``def`` nicht geht.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder