【问题标题】:python tkinter treeview not allowing modal window with direct binding like on_rightclickpython tkinter treeview不允许模态窗口直接绑定像on_rightclick
【发布时间】:2016-11-29 09:03:40
【问题描述】:

grab_set() 上直接调用函数以打开模式窗口的带有鼠标单击绑定的 Treeview 失败

tkinter.TclError: grab failed: window not viewable

如果鼠标点击首先打开一个调用模态窗口函数的弹出菜单,同样的效果也很好。

难道不能直接通过鼠标点击(最好是双击)打开模态窗口吗?

Linux Mint 17/Ubuntu 14.04、64 位、Python 3

下面是我的简单代码示例。请注意,虽然我调用了两个不同的函数,但每个函数中的代码本质上是相同的。当从弹出菜单调用时,它会给出一个模态窗口,当直接从树视图调用时,它会惨遭失败。这是预期的行为吗?

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()

【问题讨论】:

  • 可能与操作系统、python 版本或 tcl/k 版本有关。似乎在 Windows、python 3.5.2、tcl/tk 8.6 中对我有用。

标签: python tkinter modal-dialog treeview


【解决方案1】:

我也用Linux Mint 17/Ubuntu 14.04, 64bit, Python 3

您可以随时查看现有对话框的源代码并了解其工作原理。

例如检查filedialogs - 带有源代码的文件路径:

import tkinter.filedialog

print(tkinter.filedialog.__file__)

# /usr/lib/python3.5/tkinter/filedialog.py

你会看到

self.top.wait_visibility() # window needs to be visible for the grab
self.top.grab_set()

所以你必须在grab_set()之前使用wait_visibility()

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    相关资源
    最近更新 更多