Seite 1 von 1
Tkinter Button bleibt gedrückt
Verfasst: Mittwoch 4. Februar 2015, 19:05
von sedi
Hallo zusammen,
in einem Teil meines Programms muss ein *save* - Button gedrückt werden, um einen neuen Datensatz zu speichern. Vor dem Speichern wird ein Duplikattest durchgeführt. Existiert der Datensatz schon, dann wird eine Messagebox ausgegeben und die Speicherungsmethode verlassen durch
. So weit der gewollte Ablauf...
ABER:
1) Wenn ich auf den Button klicke dann senkt er sich nicht wie gewohnt. Ich klicke drauf und optisch verändert sich gar nichts. Die mit *bind* verbundene Methode wird aber ausgeführt.
2) Manchmal - ich kann den Fehler leider nicht reproduzieren - bleibt der Button nach der Aktion dann aber gedrückt??? :K
Leider weiß ich nicht wie ich den Code hier übermitteln soll, da das Projekt ganz schön groß ist und ich keine blasse Ahnung habe, wo der Fehler liegt. Außerdem könnte man es auch nicht testen, da es eine Datenbank benutzt.
Vielleicht hatte ja von euch jemand das gleiche Problem...
Re: Tkinter Button bleibt gedrückt
Verfasst: Mittwoch 4. Februar 2015, 19:29
von EyDu
Der Fehler wird wohl irgendwo in der mittels bind gebundenen Methode liegen, vielleicht zeigst du die hier. Reagiert dein Programm denn noch, nachdem du auf den Button geklickt hast? Wird die Methode korrekt verlassen, oder bleibt das Programm darin hängen?
Re: Tkinter Button bleibt gedrückt
Verfasst: Mittwoch 4. Februar 2015, 20:08
von BlackJack
Ich würde den Fehler eher darin sehen das überhaupt `bind()` verwendet wird. Das ist nicht der vorgesehene Weg um Aktionen bei Buttons zu hinterlegen. Dafür gibt es die `command`-Option.
Re: Tkinter Button bleibt gedrückt
Verfasst: Mittwoch 4. Februar 2015, 20:20
von sedi
Danke @EyDu: Das Programm reagiert vollkommen wie erwartet, nur optisch nicht.
Hier die *setup* - Methode im *Presenter* (MVP):
Code: Alles auswählen
def setup(self, *eventargs, **presets):
'''
... hier code ausgelassen, der nur die Widgets erzeugt (Views)
'''
self.view.bind_all("<Control-x>", self.presenter.close)
self.view.btn_close.bind("<Button-1>", self.presenter.close)
self.view.bind_all("<Control-s>", self.presenter.create)
self.view.btn_save.bind("<Button-1>", self.presenter.create)
self.view.btn_save.bind("<Return>", self.presenter.create)
'''
...
'''
###
# Hier die *create* - Methode
def create(self, *eventargs):
"""Der uebergeordnete Presenter/Controller ruft diese
Methode auf.
Tests:
1) alle noetigen Felder vorhanden?
2) handelt es sich um ein Duplikat?
Test ok => _create_dataset
:param eventargs:
:return:
"""
feld = self.view.get_values()
if not (feld["nachname"] or \
feld["vorname"] or \
feld["geschlecht"] or \
feld["klasse"]):
tkMessageBox.showerror("ERROR",
u"Nachname, Vorname, Klasse und Geschlecht nötig")
return 'break'
try:
schueler = Schueler.select().where(
Schueler.nachname==feld["nachname"],
Schueler.vorname==feld["vorname"],
Schueler.geschlecht==feld["geschlecht"],
Schueler.spitzname==feld["spitzname"],
Schueler.klasse==feld["klasse"],
Schueler.zweig==feld["zweig"],
Schueler.gebdat==feld["geburtstag"]
).get()
# Warnung, der Schueler existiert bereits
self.app.view.write_statusinfo(
2,
u"Schüler existiert bereits [ID=%s]!" % (schueler.id,))
except peewee.DoesNotExist:
self._create_dataset(feld)
self.listview.remove_filter()
###
# eigentliche Speicherungsmethode
def _create_dataset(self, werte):
self.presenter.schueler = Schueler.create(
nachname=werte["nachname"],
vorname=werte["vorname"],
geschlecht=werte["geschlecht"],
klasse=werte["klasse"],
heimantrag=werte["heimantrag"],
zweig=werte["zweig"],
gebdat=werte["geburtstag"],
eintritt=werte["eintritt"],
austritt=werte["austritt"],
sonstiges=werte["sonstiges"])
# View anpassen
if werte["geschlecht"] in ["W", "w"]:
self.app.view.write_statusinfo(
1, u"Schülerin eingetragen:")
self.app.view.write_statusinfo(
2, u"%s, %s [id: %s]" % (werte["nachname"],
werte["vorname"],
self.presenter.schueler.id))
else:
self.app.view.write_statusinfo(
1, u"Schüler eingetragen:")
self.app.view.write_statusinfo(
2, u"%s, %s [id: %s]" % (werte["nachname"],
werte["vorname"],
self.presenter.schueler.id))
self.view.ent_nachname.focus_set()
@BlackJack: Warum kann man einen Callback nicht mit *bind* anhängen? Wenn man MVP umzusetzen will ist das doch gar nicht anders möglich. Der View erstellt die ganzen Widgets, der Presenter kümmert sich um die Funktionalität, dh. er weist dem Widget nachträglich den Callback zu.
Re: Tkinter Button bleibt gedrückt
Verfasst: Mittwoch 4. Februar 2015, 20:40
von BlackJack
@sedi: Das kann man nicht machen weil sich Buttons dann nicht mehr so verhalten wie der Benutzer das von Buttons erwartet. Genau das ist ja gerade Dein Problem. Buttons lösen keine Aktion aus wenn man den Mouse-Button herunterdrückt wenn man sich darüber befindet. Das bewirkt erst einmal nur ein zeichnen eines gedrückten Buttons. Von da an gibt es zwei Möglichkeiten: Die Maustaste wird über dem Button losgelassen, dann wird die Aktion ausgeführt und danach der Button wieder normal gezeichnet, oder der Benutzer verlässt bei gedrückter Maustaste den Button und lässt ausserhalb los. Dann wird die Aktion *nicht* ausgelöst. Diese ganze Logik steckt im `Button` und das alles umgehst Du wenn Du selbst ein `bind()` machst. Der Button implementiert das selbst in dem er auf die verschiedenen Ereignisse reagiert, Du *musst* also die `command`-Option verwenden wenn Du das normale Standardverhalten von Buttons haben möchtest und den Benutzer nicht mit völlig anderem Verhalten irritieren willst.
Re: Tkinter Button bleibt gedrückt
Verfasst: Donnerstag 5. Februar 2015, 10:33
von sedi
Nach weiteren Tests ist aufgefallen, dass nur der Messagebox-Zweig Probleme macht. Kommentiert man in meinem Code oben die Zeilen 39 bis 41 aus, dann tritt der Fehler nicht auf.
Das ganze hat also mit der Messagebox zu tun!
@BlackJack: Deine Aussage kann ich deshalb nicht bestätigen, denn die Probleme entstehen nur, wenn diese Fehlermeldung über die Messagebox ausgegeben werden sollen. Ich habe dann den Gegentest gemacht und alle Messageboxen aus dem Code entfernt und siehe da, keine Probleme. Zu Deiner Aussage konnte ich auch im Python-Code von Tkinter selbst keinen Hinweis finden, dass das mit bind nicht klappen sollte. Vielleicht habe ich das ja auch nicht richtig verstanden - Deinen Worten entnehme ich folgenden Ablauf:
Maus über Button --> grafische Veränderung des Buttons
--> dann Mausbutton klicken --> grafische Veränderung des Buttons
--> Mausbutton wieder loslassen --> Aktion startet --> grafische Veränderung des Buttons
Das genau tritt aber nicht ein. Ist die MessageBox in den Code eingebaut, dann wird die Aktion gestartet **bevor** die grafische Veränderung des Buttons eintritt:
Maus über Button --> grafische Veränderung des Buttons
--> dann Mausbutton klicken --> **Aktion startet** (keine grafische Veränderung des Buttons!) --> Mausbutton wird im gedrückten Zustand angezeigt.
Re: Tkinter Button bleibt gedrückt
Verfasst: Donnerstag 5. Februar 2015, 12:21
von BlackJack
@sedi: Also bei mir verhalten sich Buttons so wie ich das beschrieben. Das tun sie nicht mehr wenn man `bind()` auf den Mausklick setzt statt `command` zu verwenden. Und das sollte man nicht machen wenn man den Benutzer nicht verwirren möchte. Ich verstehe auch nicht warum Du kein `command` verwenden kannst. Das ist der dafür vorgesehene Weg.
Re: Tkinter Button bleibt gedrückt
Verfasst: Donnerstag 5. Februar 2015, 17:14
von sedi
Hallo @BlackJack!
Ich habe mal einen einfachen Test geschrieben, der Deine Aussage bestätigt: keine grafische Veränderung falls das Ereignis mit *bind* angeworfen wird!
Code: Alles auswählen
import ttk
tk = ttk.Tkinter
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.btn1 = tk.Button(self,
text="normal",
command=self.click_me)
self.btn1.pack()
# bind button
self.btn2 = tk.Button(self,
text="mit bind")
self.btn2.pack()
def click_me(self, *eventargs):
tkMessageBox.showerror("ERROR", u"bla bla")
return 'break'
def main():
app = App(tk.Tk(), )
app.pack()
app.btn2.bind("<Button-1>", app.click_me)
app.mainloop()
return 0
if __name__ == '__main__':
main()
Dann muss ich jetzt 'ne Menge ändern
Warum ich das so gemacht habe? Nach jetzigem Wissensstand ist das eine berechtigte Frage...
Aber Danke