问题
Treeview with mouseclick binding that directly calls a function to open a modal window fails on grab_set()
tkinter.TclError: grab failed: window not viewable
The same works perfectly well if the mouseclick first opens a popup menu that calls the modal window function.
Is it not possible to open a modal window directly from a mouseclick (preferably doubleclick)?
Linux Mint 17/Ubuntu 14.04, 64bit, Python 3
My simple code example below. Please note that though I call two different functions, the code in each is essentially the same. When called from the popup menu it gives a modal window, when called directly from the treeview, it fails miserably. Is that expected behavior?
import tkinter as tk
from tkinter import ttk
class PopupWindow(tk.Toplevel):
def __init__(self,parent):
tk.Toplevel.__init__(self,parent)
self.parent=parent
self.protocol("WM_DELETE_WINDOW",self.destroy)
self.attributes('-topmost',True)
self.transient()
mainWindow=tk.Frame(self)
tFrame=tk.Frame(mainWindow)
self.tLabel=tk.Label(tFrame,text='Is this modal?',height=3,bd=10)
self.tLabel.pack()
self.tLabel2=tk.Label(tFrame,text=' ',height=3,bd=10)
self.tLabel2.pack()
bFrame=tk.Frame(mainWindow,bd=5)
bOK=tk.Button(bFrame,bd=1,text='Ok',command=self.destroy)
bOK.pack(side='left')
tFrame.grid(row=0,column=0)
bFrame.grid(row=1,column=0,sticky=tk.E)
mainWindow.pack()
class App:
def __init__(self):
self.root = tk.Tk()
self.tree = ttk.Treeview()
self.tree.pack()
for i in range(10):
self.tree.insert("", "end", text="Item %s" % i)
self.tree.bind("<Double-1>", self.onDoubleClick)
self.tree.bind("<Button-3>", self.onRightClick)
self.aMenu = tk.Menu(self.root, tearoff=0)
self.aMenu.add_command(label="Show 'Modal' Window",
command=lambda selection=self.tree.selection(): self.showIsModal(selection))
self.aMenu.add_separator()
self.root.mainloop()
def onRightClick(self, event):
try:
self.aMenu.selection = self.tree.identify_row(event.y)
self.aMenu.post(event.x_root, event.y_root)
finally:
self.aMenu.grab_release()
def showIsModal(self, item):
pup=PopupWindow(self.root);
pup.tLabel2['text']="Absolutely!"
pup.grab_set()
self.root.wait_window(pup)
def onDoubleClick(self, event):
item = self.tree.identify('item',event.x,event.y)
self.tree.grab_release()
self.showIsNotModal(item)
def showIsNotModal(self, item):
print("you clicked on", self.tree.item(item,"text"))
pup=PopupWindow(self.root);
pup.tLabel2['text']="Sadly no: grab_set() fails"
# following line will fail:
pup.grab_set()
self.root.wait_window(pup)
if __name__ == "__main__":
app = App()
回答1:
I use Linux Mint 17/Ubuntu 14.04, 64bit, Python 3
too.
You can always check source code of existing dialogs and see how it works.
For example check filedialogs
- path to file with source code:
import tkinter.filedialog
print(tkinter.filedialog.__file__)
# /usr/lib/python3.5/tkinter/filedialog.py
and you will see
self.top.wait_visibility() # window needs to be visible for the grab
self.top.grab_set()
So you have to use wait_visibility()
before grab_set()
def showIsNotModal(self, item):
print("you clicked on", self.tree.item(item, "text"))
pup = PopupWindow(self.root);
pup.tLabel2['text'] = "Sadly no: grab_set() fails"
pup.wait_visibility() # <-----
pup.grab_set()
self.root.wait_window(pup)
来源:https://stackoverflow.com/questions/40861638/python-tkinter-treeview-not-allowing-modal-window-with-direct-binding-like-on-ri