ButtonRelease ist nonstandard

Fragen zu Tkinter.
Antworten
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Wahrscheinlich längst bekannt bei tkinter-Benutzern, aber ich bin trotzdem geschockt: das Event ButtonRelease aktiviert das Widget, wo der Button vormals gedrückt wurde, und nicht wo er "released" wird, siehe:

Code: Alles auswählen

import tkinter as t

lb = t.Label(width=20)
lb.pack()

p1 = t.Label(width=10,text='red_paint')
p1.pack()
p1.bind('<ButtonRelease-1>',lambda event: lb.config(bg="red"))

p2 = t.Label(width=10,text='green_paint')
p2.pack()
p2.bind('<ButtonRelease-1>',lambda event: lb.config(bg="green"))

t.mainloop()
Wie kann ich das "richtige" Widget aktivieren, also das, wo der Button losgelassen wird? (wie in anderen gui-Bibliotheken auch, z.B. svg)
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Goswin

Habe es unter Kubuntu & Windows7 Starter mit Python 3.1 ausprobiert und kann kein Fehlverhalten feststellen. Also drücke ich mit der linken Maustaste auf das Label 'red_pain' passiert nichts. Lasse ich die linke Maustaste los so wird das Label oben rot eingefärbt. Drücke ich dann mit der linken Maustaste auf das Label 'green_paint' passiert nichts. Sobald ich die linke Maustaste loslasse färbt sich das Label oben grün.

Oder verstehe ich dich falsch?

Gruß wuf :wink:
Take it easy Mates!
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

@wuf: Ja, offenbar verstehst du mich falsch.

Drücke einmal mit der linken Maustate auf "red_paint", verschiebe bei gedrückter Maustaste den Zeiger auf "green_paint" (oder sonstwohin) und lasse ihn dann los. Versuche vorher zu erraten, was wohl passieren wird. (Üblicherweise kann man ja, wenn man versehentlich etwas falsch angeklickt hat, das noch bereuen und annulieren, indem man den Mauszeiger vor dem Loslassen aus dem Widget fortbewegt)

Gruß von Goswin :)
deets

Du meinst die Semantik von Tk wenn man Buttons verwendet statt Labels dazu zu missbrauchen?

Code: Alles auswählen


import Tkinter as t

lb = t.Label(width=20)
lb.pack()

p1 = t.Button(width=10,text='red_paint', command=lambda : lb.config(bg="red"))
p1.pack()

p2 = t.Button(width=10,text='green_paint', command=lambda : lb.config(bg="green"))
p2.pack()

t.mainloop()
BlackJack

@deets: Das hat überhaupt nichts mit `Button` zu tun. Es geht darum welches Widget-Binding aufgerufen wird, wenn man die Maustaste loslässt. Ich hätte auch erwartet dass es das ist, in dem sich der Mauszeiger zum Zeitpunkt des loslassens befindet. Einfach auf `Button` zu verweisen hilft nicht, denn es gibt Situationen wo man keinen `Button` verwenden kann. Beispiel: man hat einen Canvas auf dem sich bunte geometrische Objekte befinden und der Benutzer soll davon welche anklicken können, mit dem beschriebenen Verhalten, dass die Aktion zum Objekt dann ausgeführt wird, wenn die Maustaste über ihm losgelassen wird.
deets

@BlackJack

Jein. Das von Goswin beschriebene Verhalten - die Moeglichkeit, sich "umzuentscheiden" - hat sehr wohl damit zu tun. Auch in allen anderen GUI-Toolkits klickst du auf einen Button, verschiebst den Mauszeiger auf einen *anderen* Button - und bekommst *kein* Button-Release-Event auf dem neuen, noch auf dem alten Button. Und genau dieses Verhalten zeitigt Tk auch, wenn man eben Buttons verwendet.

Dass andere Toolkits mit genrellen Button-Release-Events anders umgehen mag sein. Ich wuerde ja mal versuchen, ob man das ganze durch binden des Button-Release auf dem parent-Widget loesen kann. Theoretisch sollte man ja zumindest ueber die Event-Koordinaten und die View-Hierarchie rauskriegen, wer der Empfaenger sein *sollte*. Ob das praktisch geht kann ich aber nicht wirklich sagen.
lunar

@deets Ganz allgemein geht es aber auch darum, dass es der naiven Erwartung vollkommen widerspricht, wenn ein Release-Event in einem Widget ausgelöst wird, über dem der Mauszeiger sich gar nicht befand, als die Maustaste losgelassen wurde.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Goswin

Habe dich effektiv falsch verstanden. Es verhält sich genau so wie du festgestellt hattest. Ich weiss nicht wie dies bei PyQt, wxPython usw. aussieht. Das Snippet von deets mit den Button-Widgets und der 'command'-Option scheint sich richtig zu verhalten. Wenn man mit Tkinter arbeitet sind Überraschungen vorprogrammiert. Da ist man wieder einmal gezwungen in die Gerümpelkammer zu gehen und etwas zusammen zu bauen. Wie es ein Kunstschmied / -Schlosser macht. :lol:

Habe es versucht mit etwas Code zu lösen:

Code: Alles auswählen

import tkinter as t
from functools import partial

def change_color(color, event):
    xpos = event.x
    ypos = event.y
    widget_width = event.widget.winfo_width()
    widget_height = event.widget.winfo_height()
    
    if xpos <= widget_width and ypos <= widget_height:
        lb.configure(bg=color)
    
lb = t.Label(width=20)
lb.pack()

p1 = t.Label(width=10,text='red_paint')
p1.pack()
p1.bind('<ButtonRelease-1>', partial(change_color, 'red'))

p2 = t.Label(width=10,text='green_paint')
p2.pack()
p2.bind('<ButtonRelease-1>', partial(change_color, 'green'))

t.mainloop()
Funktion ohne Gewähr.

Gruß wuf :wink:
Take it easy Mates!
Antworten