我是一个Python的初学者,对Python的基础知识和一点OOP的基础知识进行了非常少的培训。我试图制作一个可以重定向到多个页面的GUI,我的GUI如下所示:
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox as mx
from PIL import Image, ImageTk
import tkinter.scrolledtext as tkst
# Initialize The Planar code Changing Functionality frame
class PGcodefixer(ttk.Frame):
def __init__(self, container, controller):
super().__init__(container)
self.config(width = 950, height = 587)
self.controller = controller
self.pack_propagate(False)
self.grid_propagate(False)
self.errflag = 0
# Initialize Labels
self.img3 = Image.open(r"C:\some\path\here")
self.img32 = self.img3.resize((250,250), Image.Resampling.LANCZOS)
self.img3final = ImageTk.PhotoImage(self.img32)
# Initialize styling of ttk widgets
self.style = ttk.Style(self)
self.style.theme_use("alt")
self.style.configure("Heading.TLabel", font = ("Comic Sans MS", "20", "bold"), justify = "center", compound = "top", background = "#568BFC", foreground = "white")
self.style.configure("TLabel", font = ("Comic Sans MS", "15", "bold"), justify = "center", compound = "top", background = "#568BFC", foreground = "white")
self.style.configure("TButton", font = ("Comic Sans MS", "11", "bold"), justify = "center", Expand = True, background = "#FCC756", foreground = "white")
self.style.configure("TEntry", justify = "center", Expand = True, background = "#FCC756", foreground = "Black")
self.style.configure("TFrame", background = "#568BFC") # Background color in Hexcode
# Initialize The Nonplanar code Changing Functionality frame (Work in progress)
class NPGcodefixer(ttk.Frame):
def __init__(self,container, controller):
super().__init__(container)
self.controller = controller
self.config(width = 950, height = 587)
self.pack_propagate(False)
self.grid_propagate(False)
# Initialize Labels
self.img2 = Image.open(r"C:\some\path\here")
self.img22 = self.img2.resize((200,200), Image.Resampling.LANCZOS)
self.img2final = ImageTk.PhotoImage(self.img22)
# Initialize the styling of ttk widgets
self.style = ttk.Style(self)
self.style.theme_use("alt")
self.style.configure("TLabel", font = ("Comic Sans MS", "16", "bold"), justify = "center", compound = "top", background = "#DDE805", foreground = "white")
self.style.configure("TButton", font = ("Comic Sans MS", "11", "bold"), justify = "center", Expand = True, background = "#F57FF1", foreground = "white")
self.style.configure("TFrame", background = "#DDE805")
# Initialize The Homepage Frame
class Homepage(ttk.Frame):
def __init__(self, container, controller):
super().__init__(container)
self.controller = controller
self.config(width = 950, height = 587)
self.pack_propagate(False)
self.grid_propagate(False)
# Initialize Labels (The first two lines correspond to how you are supposed to put an image into tkinter using Pillow)
self.img1 = Image.open(r"C:\some\path\here")
self.img12 = self.img1.resize((200,200), Image.Resampling.LANCZOS)
self.img1final = ImageTk.PhotoImage(self.img12)
self.labelh1 = ttk.Label(self, image = self.img1final, text = "Welcome to the Timesaver!\n Select the function you wish to use").place(relx = 0.315, rely = 0.15)
# Initialize Button
self.buttonh1 = ttk.Button(self, text = "Planar Gcode Compiler", command = controller.showframe(self = App, frame = "PGcodefixer")).place(relx = 0.2255, rely = 0.65)
self.buttonh2 = ttk.Button(self, text = "Nonplanar Gcode Compiler", command = controller.showframe(self = App, frame = "NPGcodefixer")).place(relx = 0.55, rely = 0.65)
self.buttonh3 = ttk.Button(self, text = "About", command = self.AboutMsg).place(relx = 0.85, rely = 0.9)
# Initialize the styling of ttk Widgets
self.style = ttk.Style(self)
self.style.theme_use("alt") # To enable the button color to be changed, standard ttk will not allow it.
self.style.configure("TLabel", font = ("Comic Sans MS", "16", "bold"), justify = "center", compound = "top", background = "#FFB6C1", foreground = "white") # Compound method for relative positioning of text and Image
self.style.configure("TButton", font = ("Comic Sans MS", "11", "bold"), justify = "center", Expand = True, background = "#67EB67", foreground = "white")
self.style.configure("TFrame", background = "#FFB6C1") # Background color in Hexcode
# Initialize a popup about Window for those interested to know more
def AboutMsg(self):
mx.showinfo(title = 'About', message =
'Multi-Purpose Timesaver ver1.0\n'
'Designed by X')
# 5. Initialize App as a class
class App(tk.Tk):
def __init__(self):
super().__init__()
# Initializing Window
self.title("IMPT - Internship Multi-Purpose Timesaver") # Window Title
self.geometry("950x587") # Using Golden Ratio, haha. Just the Window Size
self.resizable(False, False)
H = Homepage(self, App).pack()
P = PGcodefixer(self,App).pack()
N = NPGcodefixer(self,App).pack()
self.frames = {"Homepage": H, "PGCodefixer": P, "NPGcodefixer": N}
def showframe(self, frame):
if frame in self.frames.keys():
print("yes")
self.frames[frame].tkraise(self) #The self was asked for by vscode as positional argument is missing without it.
else:
print("no")
pass
# 6. Bootstrapping the App
if __name__ == "__main__":
app = App()
App.showframe("Homepage")
app.mainloop()
我对三个主要问题感到困惑,并将非常感谢您的帮助。
- super(init)container是如何工作的?特别是对于在顶部初始化的第一帧-容器是从哪个类继承的?
1.为什么控制器和self在代码中无法识别(即controller.function根本不执行(用print语句检查)
1.与2有关。- 我考虑在最顶层初始化一个mixin类来存储tkraise方法(将来还有其他方法)和帧字典,但发现这相当奇怪(即它会提升一些帧(特别是它们的背景颜色和按钮颜色),但不会提升它们的按钮或其他窗口小部件,这些窗口小部件与前一帧的窗口小部件保持相同。这是实现框架tkraise方法的一个可能的解决方案吗?我目前的解决方案(就方法论而言)是一个好的解决方案吗?
再次感谢你的帮助。很多在线tkraise方法的解决方案都使用了tk.frame,但是我还没有找到一个使用ttk.frame的解决方案,所以我很困惑。我是一个初学者在编程GUI方面(甚至一般的编程-我试图通过尝试和错误来学习),这是我在tkinter上的第一个主要步骤,所以即使你有任何提示来提供我的代码结构/糟糕的编程实践(例如:时间复杂度O(n)等)为了避免我正在做的,我会非常感谢他们以及!
编辑:包含了几行缺失的代码,显示了tkraise的实现,并添加了控制器到控制器类的分配。
EDIT 2:添加了控制器函数的self分配,因为它们是方法。
EDIT 3:我还意识到在进一步的测试中str(classname)不等于“classname”,所以我改变了标准。在从按钮调用showframe方法时,它只是由于某种原因而没有执行,这真的让我很困惑。为什么会出现这种情况呢?我想在字符串列表中使用类型更改方法(if str(x)),以避免不必要地创建多个重复的类示例。我现在很失落,至于我的方法是否是甚至正确的一个在这里实施tkraise。请帮助!!
编辑4:考虑到Roberts先生的建议,将框架的示例添加到列表中。但是现在弹出了一个AttributeError,表明self.frames不是App的属性,尽管它是App示例中初始化的字典。我该如何继续?
修正了tkraise的错误示例为self.frames[frame].tkraise(self),并修正了import语句中的另一个错别字
2条答案
按热度按时间t5zmwmid1#
1.*
super(init)
是如何工作的?*你可不是这样的。你所拥有的是
super().__init__
。第一个类(PGcodefixer
)继承自ttk.Frame
,所以super().__init__
与输入ttk.Frame.__init__
是相同的。如果你的类继承自多个父类,super()
的处理会更加复杂,但是如果你只是从一个基类派生,这个概念就很简单了。1.为什么控制者和自我不被认可…
您有
controller
作为构造函数的参数,但是您没有将该参数保存在任何地方。如果你以后需要它,你需要做一些类似self.controller = controller
的事情,以便以后可以参考它。请记住,
self
在任何方面都不是魔法。这只是一个参数名。按照惯例,类方法中的第一个参数被称为self
,但像所有函数参数一样,它只在函数的生命周期内持续。不像this
是C++,你可以使用另一个名字,但你会赢得Python社区永恒的嘲笑。1.我是为了钱?
我在代码中没有看到tkraise,所以我不知道你在说什么。Mixins是减少重复输入的一种有用的方法,但前提是代码真正“通用”。如果你要添加例外和特殊情况,那么这可能不是一个好主意。
chhkpiq42#
您的代码中有几个问题:
在上面的代码中:
command = controller.showframe(...)
将执行controller(...)
* 立即 *,并将结果(即None
)分配给command
选项,因此稍后单击按钮将不会执行任何操作。使用command = lambda: controller.showframe(...)
代替controller.showframe(self = App, frame = "...")
应为controller.showframe("...")
H = Homepage(self, App).pack()
将把.pack()
的结果赋值给H
,所以H
将是None
。将线分成两行:H = Homepage(...)
和H.pack()
(实际上在这里使用.pack()
并不适合您的情况)。P
和N
也是如此。App
作为 * 控制器 * 是错误的,请改用self
在上面的代码中,
self.frames[frame].tkraise(self)
应该是self.frames[frame].tkraise()
所以更新后的代码应该如下: