Reputation: 20076
I'm running into this really strange behavior with Toplevel
windows, I have some logic like so:
Did user click 'properties button?'
yes? bind <ButtonPress-1> to window that will call properties(mouselocation)
properties(mouselocation):
find location of cursor
create property window at cursor
The problem I'm running into is that somehow, when I create multiple windows and attempt to close one, they all close. I've managed to create a minimal example which highlights my issue, the PropertiesDialog
class is exactly what I'm using minus a couple small changes so it can work for this example:
from Tkinter import *
class PropertyDialog(Toplevel):
def __init__(self, root, string):
Toplevel.__init__(self)
self.wm_overrideredirect(1)
self.\
geometry('+%d+%d' %
(root.winfo_pointerx(),
root.winfo_pointery()))
try:
self.tk.call('::Tk::unsupported::MacWindowStyle',
'style', self._w,
'help', 'noActivates')
except TclError:
pass
window_frame = Frame(self)
window_frame.pack(side=TOP, fill=BOTH, expand=True)
exit_frame = Frame(window_frame, background='#ffffe0')
exit_frame.pack(side=TOP, fill=X, expand=True)
button = Button(exit_frame, text='x', width=3, command=self.free,
background='#ffffe0', highlightthickness=0, relief=FLAT)
button.pack(side=RIGHT)
text_frame = Frame(window_frame)
text_frame.pack(side=TOP, fill=BOTH, expand=True)
label = Label(text_frame, text=string, justify=LEFT,
background='#ffffe0',
font=('tahoma', '8', 'normal'))
label.pack(ipadx=1)
def free(self):
self.destroy()
def bind():
"""
toggle property window creation mode
"""
root.bind('<ButtonPress-1>', create)
def create(event):
"""
Create actual window upon mouse click
"""
t = PropertyDialog(root, 'help me')
return
root = Tk()
root.geometry('%dx%d' % (300,400))
Button(root, text='create', command=bind).pack()
root.mainloop()
Now if you run this application, click create
and click on random areas of the window then attempt to close one. For one reason, every window closes upon attempting to destroy just one. What am I doing wrong to create this behavior?
Upvotes: 1
Views: 552
Reputation: 49320
The other windows aren't being destroyed, they're simply being hidden by the main window. You can see them if you create some popups, close one of them, then move the main window.
To fix this, lower the main window below all the others. The changed areas are marked with #CHANGED#
:
from Tkinter import *
class PropertyDialog(Toplevel):
def __init__(self, root, string):
Toplevel.__init__(self)
self.wm_overrideredirect(1)
self.root = root #CHANGED# save a reference to the root
self.\
geometry('+%d+%d' %
(root.winfo_pointerx(),
root.winfo_pointery()))
try:
self.tk.call('::Tk::unsupported::MacWindowStyle',
'style', self._w,
'help', 'noActivates')
except TclError:
pass
window_frame = Frame(self)
window_frame.pack(side=TOP, fill=BOTH, expand=True)
exit_frame = Frame(window_frame, background='#ffffe0')
exit_frame.pack(side=TOP, fill=X, expand=True)
button = Button(exit_frame, text='x', width=3, command=self.free,
background='#ffffe0', highlightthickness=0, relief=FLAT)
button.pack(side=RIGHT)
text_frame = Frame(window_frame)
text_frame.pack(side=TOP, fill=BOTH, expand=True)
label = Label(text_frame, text=string, justify=LEFT,
background='#ffffe0',
font=('tahoma', '8', 'normal'))
label.pack(ipadx=1)
def free(self): #CHANGED# this method significantly
self.destroy() # first we destroy this one
for val,widget in enumerate(dialogs): # go through the dialogs list
if widget is self: # when we find this widget
dialogs.pop(val) # pop it out
break # and stop searching
if dialogs: # if there are any dialogs left:
for widget in dialogs: # go through each widget
widget.lift(aboveThis=self.root) # and lift it above the root
def bind():
"""
toggle property window creation mode
"""
root.bind('<ButtonPress-1>', create)
def create(event): #CHANGED# this to store the widget in a list
"""
Create actual window upon mouse click
"""
dialogs.append(PropertyDialog(root, 'help me'))
root = Tk()
dialogs = [] #CHANGED# to initialize a list
root.geometry('%dx%d' % (300,400))
Button(root, text='create', command=bind).pack()
root.mainloop()
Upvotes: 2