Ich möchte jedesmal dann ein Event aktivieren, wenn ich mit der Maus auf eine Teilfläche meines Fensters klicke, die durch einen Frame begrenzt ist.
Rein theoretisch könnte ich den definierenden Frame an das Mausevent binden, aber praktisch funktioniert das nicht, weil dieser Frame Labels und andere Kind-Widgets enthält, und es dann nicht zur Kenntnis nimmt, wenn ich zufälligerweise auf eines dieser Kindwidgets klicke. So etwas ist *nicht erwünscht*: das Event soll immer aktiviert werden, egal ob ich auf den Frame oder irgendeines der Kind- oder Enkelwidgets klicke.
Wenn ich zuoberst auf sämtliche Kindevents ein transparentes Label oder Canvas mit den Dimensionen des Frames legen könnte, dann könnte ich dieses transparente Label oder Canvas an das Event binden. Aber das funktioniert ja schon deshalb nicht, weil (1)_es in tkinter anscheinend keine transparenten Widgets gibt, und (2)_ich nicht wüsste, was ich als Elternwidget für das transparente Widget nehmen kann, ohne die Kindwidgets von ihrem Ort zu verdrängen.
Gibt es dafür eine Lösung? Oder besteht die beste Lösung darin, tkinter zu vergessen und ein anderes GUI-Tool zu benutzen?
Widgetbeladenne Fensterfläche anklicken
Hi Goswin
Was hältst du von dieser Lösung?:
Gruss wuf
Was hältst du von dieser Lösung?:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
try:
#~~ For Python 2.x
import Tkinter as tk
except ImportError:
#~~ For Python 3.x
import tkinter as tk
def event_callback(event):
if str(main_frame) in str(event.widget):
print('Bingo! MainFrame-Event')
app_win = tk.Tk()
app_win.geometry('300x300')
app_win.bind('<Button-1>', event_callback)
main_frame = tk.Frame(app_win, width=200, height=200, bg='yellow')
main_frame.propagate(False)
main_frame.pack(expand=True)
sub_frame = tk.Frame(main_frame, width=100, height=100, bg='green')
sub_frame.propagate(False)
sub_frame.pack(expand=True)
canvas = tk.Canvas(sub_frame, width=50, height=50, bg='blue')
canvas.pack(expand=True)
app_win.mainloop()
Take it easy Mates!
- Goswin
- User
- Beiträge: 363
- Registriert: Freitag 8. Dezember 2006, 11:47
- Wohnort: Ulm-Böfingen
- Kontaktdaten:
@wuf:
Vielen Dank, deine Lösung funktioniert offenbar - zumindest auf meinem Rechner!
Ich weiß aber immer noch nicht, wo nun der feine Unterschied zwischen einem Tk-Objekt, Toplevel-Objekt, und einem beliebigen Frame besteht, mein Python-Handbuch ist veraltet und sagt nichts darüber. Reagiert das Tk-Objekt auf sämtliche Events, die für irgendein Widget stattfinden? Gilt das für beliebige Toplevel-Objekte?
Und nicht zuletzt: Ist die verwendete str-Darstellung der Subframes und Widgets Standard oder implementierungsabhängig? Wird sie irgendwo offiziell beschrieben?
Vielen Dank, deine Lösung funktioniert offenbar - zumindest auf meinem Rechner!
Ich weiß aber immer noch nicht, wo nun der feine Unterschied zwischen einem Tk-Objekt, Toplevel-Objekt, und einem beliebigen Frame besteht, mein Python-Handbuch ist veraltet und sagt nichts darüber. Reagiert das Tk-Objekt auf sämtliche Events, die für irgendein Widget stattfinden? Gilt das für beliebige Toplevel-Objekte?
Und nicht zuletzt: Ist die verwendete str-Darstellung der Subframes und Widgets Standard oder implementierungsabhängig? Wird sie irgendwo offiziell beschrieben?
@Goswin: Das Tkinter-Buch vom Effbot ist immer wieder hilfreich: http://effbot.org/tkinterbook/tkinter-e ... ndings.htm
Da stehen die vier Ebenen für die man `bind()` verwenden kann beschrieben und in welcher Reihenfolge die aufgerufen werden.
Die Zeichenkettendarstellung eines Widget-Objekts ist laut Docstring der Tk-Pfadname. Widgets sind in Tk in einer Hierarchie angeordnet mit '.' als Wurzel/Pfadtrenner. Die Tk-Namen für die Widgets würfelt Tkinter irgendwie aus aber ansonsten ist das Format schon (Tk-)Standard.
Tkinter ist ja nur eine *sehr* dünne Schicht über dem Tk-Interpreter. Oft hilft es sich in Tk-Dokumentation einzulesen wenn man mehr Informationen benötigt als die Tkinter-Dokumentation hergibt.
Da stehen die vier Ebenen für die man `bind()` verwenden kann beschrieben und in welcher Reihenfolge die aufgerufen werden.
Die Zeichenkettendarstellung eines Widget-Objekts ist laut Docstring der Tk-Pfadname. Widgets sind in Tk in einer Hierarchie angeordnet mit '.' als Wurzel/Pfadtrenner. Die Tk-Namen für die Widgets würfelt Tkinter irgendwie aus aber ansonsten ist das Format schon (Tk-)Standard.
Tkinter ist ja nur eine *sehr* dünne Schicht über dem Tk-Interpreter. Oft hilft es sich in Tk-Dokumentation einzulesen wenn man mehr Informationen benötigt als die Tkinter-Dokumentation hergibt.
- Goswin
- User
- Beiträge: 363
- Registriert: Freitag 8. Dezember 2006, 11:47
- Wohnort: Ulm-Böfingen
- Kontaktdaten:
@wuf:
Für das was ich anstrebe, funktioniert deine Lösung leider doch nicht oder ich verstehe sie nicht richtig.
Genauer gesagt: sie funktioniert anscheinend nicht, wenn ich zwischen mehrere verschiedenen Frames unterscheiden muss; im unteren Beispiel ordnet sie das ButtonRelease-Event demselben Frame zu wie das letztaktivierte Button-Event, obwohl ich die Maustaste über einem anderen Frame loslasse:
Auf welches Widget wird 'event.widget' beim Aufreten von 'event' gesetzt? Offenbar nicht auf das Widget, wo das Event 'event' stattfindet!
Für das was ich anstrebe, funktioniert deine Lösung leider doch nicht oder ich verstehe sie nicht richtig.
Genauer gesagt: sie funktioniert anscheinend nicht, wenn ich zwischen mehrere verschiedenen Frames unterscheiden muss; im unteren Beispiel ordnet sie das ButtonRelease-Event demselben Frame zu wie das letztaktivierte Button-Event, obwohl ich die Maustaste über einem anderen Frame loslasse:
Code: Alles auswählen
#!/usr/bin/python3
#coding=utf8
import tkinter as tk
def main():
def click_callback(event):
print(str(mainframe1),str(mainframe2),str(event.widget))
if str(mainframe1) in str(event.widget):
print(str(mainframe1),str(event.widget))
print('MainFrame1-Click')
if str(mainframe2) in str(event.widget):
print('MainFrame2-Click')
def release_callback(event):
print(str(mainframe1),str(mainframe2),str(event.widget))
if str(mainframe1) in str(event.widget):
print('MainFrame1-Release')
if str(mainframe2) in str(event.widget):
print('MainFrame2-Release')
app_win = tk.Tk()
app_win.geometry('600x300')
app_win.resizable(False,False)
app_win.bind('<Button-1>', click_callback)
app_win.bind('<ButtonRelease-1>', release_callback)
mainframe1 = tk.Frame(app_win, width=200, height=200, bg='cyan')
mainframe1.propagate(False)
mainframe1.pack(expand=True,side=tk.LEFT)
#
subframe1 = tk.Frame(mainframe1, width=100, height=100, bg='green')
subframe1.propagate(False)
subframe1.pack(expand=True)
mainframe2 = tk.Frame(app_win, width=200, height=200, bg='yellow')
mainframe2.propagate(False)
mainframe2.pack(expand=True,side=tk.LEFT)
#
subframe2 = tk.Frame(mainframe2, width=100, height=100, bg='red')
subframe2.propagate(False)
subframe2.pack(expand=True)
app_win.mainloop()
if __name__ == '__main__': main()
@Goswin: Alle Mausereignisse zwischen 'ButtonPress' und 'ButtonRelease' (inklusive) werden an das gleiche Widget gesendet welches das 'ButtonRelease'-Ereignis empfangen hat. Steht auch so beim Effbot dokumentiert. Du könntest Dir bei der Behandlung vom 'ButtonRelease' die `x_root`- und `y_root`-Attribute vom Ereignisobjekt nehmen und mit `Widget.winfo_containing()` das Widget an dieser Position geben lassen. Ungetestet.
Hi Goswin
Dank dem Tipp von BlackJack habe ich noch folgendes ausprobiert:
Gruss wuf
Dank dem Tipp von BlackJack habe ich noch folgendes ausprobiert:
Code: Alles auswählen
#!/usr/bin/python3
#coding=utf8
import tkinter as tk
def main():
def click_callback(event):
event_path = event.widget.winfo_containing(event.x_root, event.y_root)
if str(mainframe1) in str(event_path):
print(str(mainframe1),str(event.widget))
print('MainFrame1-Click')
if str(mainframe2) in str(event_path):
print(str(mainframe2),str(event.widget))
print('MainFrame2-Click')
def release_callback(event):
event_path = event.widget.winfo_containing(event.x_root, event.y_root)
print(event_path)
if str(mainframe1) in str(event_path):
print(str(mainframe1),str(event.widget))
print('MainFrame1-Release')
if str(mainframe2) in str(event_path):
print(str(mainframe2),str(event.widget))
print('MainFrame2-Release')
app_win = tk.Tk()
app_win.geometry('600x300')
app_win.resizable(False,False)
app_win.bind('<Button-1>', click_callback)
app_win.bind('<ButtonRelease-1>', release_callback)
mainframe1 = tk.Frame(app_win, width=200, height=200, bg='cyan')
mainframe1.propagate(False)
mainframe1.pack(expand=True,side=tk.LEFT)
#
subframe1 = tk.Frame(mainframe1, width=100, height=100, bg='green')
subframe1.propagate(False)
subframe1.pack(expand=True)
mainframe2 = tk.Frame(app_win, width=200, height=200, bg='yellow')
mainframe2.propagate(False)
mainframe2.pack(expand=True,side=tk.LEFT)
#
subframe2 = tk.Frame(mainframe2, width=100, height=100, bg='red')
subframe2.propagate(False)
subframe2.pack(expand=True)
app_win.mainloop()
if __name__ == '__main__': main()
Take it easy Mates!