Python Tkinter GUI文件菜单不显示,尽管GUI是可操作的



我对Python相对陌生,我确信这是我的代码结构中的一个错误,但我似乎无法在GUI中显示文件菜单。有人能告诉我我在文件菜单中犯了什么错误吗?另外,我很抱歉,但是复制和粘贴后的间距有点偏离。类缩进级别对我来说是合适的。我使用的是Python 3.71

任何其他关于更好或更具Python风格的方式来完成我在这里所做的事情的评论也欢迎并感谢您的提前帮助!

from tkinter import *
from tkinter import ttk
import tkinter.scrolledtext as tkst
import os
import tkinter as tk
from functools import partial
from PIL import Image, ImageTk
class UserGui(tk.Tk):
def __init__(self,parent):
self.parent=parent
self.widgets()
def widgets(self):
self.parent.configure(bg='white')
self.frame1_style = ttk.Style()
self.frame1_style.configure('My.TFrame', background='white')
self.frame2_style = ttk.Style()
self.frame2_style.configure('My2.TFrame',background='white')
self.parent.title("TGUI")

self.frame1 = ttk.Frame(self.parent, style='My.TFrame') #Creating Total Window Frame 1
self.frame1.grid(row=0, column=0, sticky=(N, S, E, W))
self.frame2 = ttk.Frame(self.parent, width=100, height=20, style='My2.TFrame')
self.frame2.grid(row=0, column=6, padx=20, pady=5)

#Menu Creation
self.menu1 = tk.Menu(self.parent, tearoff=0)
self.parent.config(menu=self.menu1)
self.fileMenu = tk.Menu(self.menu1, tearoff=0)
self.fileMenu.add_command(label="Open", command=self.donothing)
self.fileMenu.add_command(label="Save", command=self.donothing)
self.fileMenu.add_separator()
self.fileMenu.add_command(label="Exit", command=self.parent.quit)
self.fileMenu.add_cascade(label="File", menu=self.menu1)
self.editMenu = tk.Menu(self.menu1, tearoff=0)
self.editMenu.add_command(label="Cut", command=self.donothing)
self.editMenu.add_command(label="Copy", command=self.donothing)
self.editMenu.add_command(label="Paste", command=self.donothing)
self.editMenu.add_cascade(label="Edit", menu=self.menu1)    
def donothing(self):
filewin = Toplevel(self.parent)
button = Button(filewin, text="Do nothing button")
button.pack()

def main():
root=tk.Tk()
ug=UserGui(root)
root.mainloop()
if __name__ == '__main__':
main()

编辑1,2,3:我已经用menu=self.menu1更正了menuadd_cascade选项,但我仍然没有显示文件菜单。

EDIT:很抱歉我没有及时注意到Python-3标记,除了在出错时直接调用super().__init__而不是Frame.__init__之外,其他都一样。这会让它更像Py3。即便如此,这应该仍然有效。

奇怪的是,将menu.config向下推到run函数对我来说很有效——尽管它看起来应该像你做的那样工作

def main():
root=tk.Tk()
ug=UserGui(root)
root.config(menu=ug.fileMenu)
root.mainloop()
if __name__ == '__main__':
main()

此外,还有一些东西可以让它更像OOP,可读性更强。这就是我通常制作GUI的方式。其想法是将GUI拆分为Frames,然后执行类似的操作。也就是说,你的应用程序可以有左框和右框,其中右框将容纳文本框,而左框实际上有两个子框——一个子框用于名称和下拉列表,另一个子框则用于按钮。这样,每个单独的功能都由框架本身处理,而不是全部在一个巨大的类中,这些框架中的元素是相对于框架的网格本身放置的,而所有框架都放置在主框架的网格中。这样还可以将大量代码拆分为模块,并有助于提高可维护性。

子帧通过MainFrame传播来发射"全局"事件(困扰其他帧的事件),这就是为什么它们都携带一个self.part(其父帧)和一个self-root(MainFrame)。MainFrame也是我喜欢在其中放置类似self.data的东西的Frame,CCD_8本身是一个独立的类(在Tkinter之外),它处理所有的数据输入/输出和逻辑,这样就不会将GUI代码逻辑与数据计算和逻辑混淆。理想情况下,Data类将处理数据错误,GUI只需要处理逻辑中的任何错误(例如从下拉菜单中选择两个不可能组合的选项)

from tkinter import *
from tkinter import ttk
class SubFrame(Frame):
def __init__(self, parent, text="Top Right"):
Frame.__init__(self)
self.pack()  
self.parent = parent
self.root = parent.root
self.label=Label(self, text=text).pack()

class RightFrame(Frame):
def __init__(self, parent):
Frame.__init__(self, relief=RAISED, borderwidth=1)
self.pack(side=RIGHT, fill=BOTH, expand=1)
self.root = parent
self.label = Label(self, text="Right Frame").pack()

class LeftFrame(Frame):
def __init__(self, parent):
Frame.__init__(self, relief=RAISED, borderwidth=1)
self.pack(side=LEFT, fill=BOTH, expand=1)
self.root = parent
self.label = Label(self, text="Left Frame").pack()
#again Frames which would have a parent class RightFrame and root MainFrame
self.subFrame1 = SubFrame(self)
self.subFrame2 = SubFrame(self, text="Top Right SubFrame 2") 
class MainFrame(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry("1100x600")
self.title("Working Example")
self.leftFrame = LeftFrame(self)
self.rightFrame = RightFrame(self)
#self.data = MagicalDataHandlingClass()

def run():
app = MainFrame()
app.mainloop()

编辑对太长而不适合的评论的回答

之所以调用Frame.__init__(...),是因为类定义看起来像class LeftFrame(Frame)。通常要声明一个类,您要编写的只是class LeftFrame。当您在()中添加位时,所发生的事情称为继承。当您从类(称为父类)继承时,您的类(称为子类)将继承父类的所有方法和属性。但就像你必须初始化你的类才能得到一个对象一样,即lf = LeftFrame(...),父类也必须初始化。在Python中,这个初始化是通过调用特殊的dunder__init__(...)函数来完成的。因此,对Frame.__init__(...)的调用之所以发生,是因为您需要告诉父类它需要哪些值才能正常工作。然而,在Python3中,建议您不要像super().__init__(....)那样使用super函数来实例化父级。发生这种情况有很多复杂的原因,其中大多数你可能暂时不必担心(例如,如果你同时从多个类继承,如果你从一个从不同类继承的类继承,等等…)Python 3只要做super().__init__(...),即使你不理解,也会做你想做的事情。如果你想让自己不知所措,Raymond Hettinger写了一篇很好的《超级就是超级》,以及为什么它比以前好得多。

考虑到@JasonHarper没有将此答案复制到答案格式,我希望其他人能够从帖子中受益,我将发布此答案以确保完整性。

关键是我在子Menu小部件对象上调用add_cascade的对象,而不是名为self.menu1的主Menu小部件对象。钥匙在变:

self.fileMenu.add_cascade(label="File", menu=self.menu1)

至:

self.menu1.add_cascade(label="File", menu=self.fileMenu)

这是将fileMenuMenu对象添加到self.menu1的总Menu小部件对象的正确方式。

最新更新