Tkinter 网格管理器无法管理 '顶层窗口' 菜单

1 投票
2 回答
4389 浏览
提问于 2025-04-20 01:57

我有一个用Python 3和Tkinter写的应用程序。我现在想在弹出的窗口顶部添加一个菜单栏。创建菜单栏没问题,但一旦我尝试用grid()来布局它,就出现了问题,并给我抛出了一个错误:

[first line omitted]
File "C:\Users\Me\Documents\sync.py", line 13 in __init__
  self.createWidgets()
File "C:\Users\Me\Documents\sync.py", line 21, in createWidgets
  self.menubar.grid(column = 0, comlumnspan = 3)
File "C:\Program Files (x86)\Python34\lib\tkinter\__init__.py", line 2020, in grid_configure + self._options(cnf,kw))
_tkinter.TclError: can't manage ".41452544.49048880": it's a top-level window

从这个错误来看,流程是正常的:__init__调用createWidgets,创建了self.menubar,添加了子菜单,然后调用self.menubar.grid

我搞不明白的是,为什么Tkinter会认为我想要布局的菜单栏是一个顶层窗口。self.menubar.grid()在错误追踪中被列出,显然是问题的根源,而不是根窗口,所以它一定是这样认为的。

这是相关的代码片段:

def createWidgets(self):
    self.menubar = tk.Menu(self)
    self.menubar.grid(column = 0, columnspan = 3)

    SyncMenu = tk.Menu(self.menubar, tearoff = 0)
    SyncMenu.add_command(label = "Connect", command = self.Sync.Connect)
    SyncMenu.add_command(label = "Disconnect", command = self.Sync.Disconnect)

    FileMenu = tk.Menu(self.menubar, tearoff = 0)
    FileMenu.add_command(label = "Upload File", command = self.File.Upload)
    FileMenu.add_command(label = "Browse Online Files", command = self.File.Browse)

    self.menubar.add_cascade(label = "Sync", menu = SyncMenu)
    self.menubar.add_cascade(label = "File", menu = FileMenu)

无论我把grid()的调用放在哪里,都会出现同样的错误。

这个问题的另一个方面是,我使用的是Python 3和更新的Tkinter,所以我不能使用tk.Tk()。相反,我是这样初始化的:

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self,master)
        self.grid()
        self.createWidgets()
        self.master.geometry("500x500")

2 个回答

0

我搞明白了。当我编辑问题,添加第二个代码块时,我注意到了那行 self.master.geometry,我心想:“这一行是影响主窗口的,我能不能用这个呢?”

答案是可以的,所以找到根窗口的解决办法就是使用 self.master,这个在我的 __init__ 方法里通过调用 tk.Frame.__init__ 定义的:

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self,master)    # This line defines self.master
        self.grid()
        self.createWidgets()
        self.master.geometry("500x500")   # This line uses it

所以,现在把我的菜单栏放到正确窗口的解决办法就是这样:

self.master["menu"] = self.menubar

这段代码是在创建所有菜单和菜单项之后的。

7

你不能在菜单上使用网格布局。因为 Tkinter 把菜单看作是一个顶层窗口,它们会浮在其他窗口的上面。

创建一个传统的菜单栏的正常方式是把它和根窗口的 menu 属性关联起来:

root = tk.Tk()
menubar = tk.Menu(root)
...
root.configure(menu=menubar)

撰写回答