如何在多个 windows Tkinter 程序中保持不变的布局?

How to keep a constant layout in multiple windows Tkinter program?

我正在开发一个 Python Tkinter 应用程序,预计会有多个 windows。同时,我想保持某些布局(背景图像,Top/bottom 标签)不变。我尝试设置背景图片 (b_image) 和左上角标签 (topleft_label),但它没有显示。有人可以看看这个片段并建议如何实现吗?

import tkinter as tk

LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1024

class MainApp(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Sales System") # set the title of the main window
        self.geometry("%dx%d+0+0" % (WIDTH, HEIGHT)) # set size of the main window to 300x300 pixels

        container = tk.Frame(self)

        b_image = tk.PhotoImage(file='background.png')
        b_label = tk.Label(container, image=b_image)
        b_label.place(relwidth=1, relheight=1)

        topleft_label = tk.Label(container, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
        topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')

        container.pack(side="top", fill="both", expand = True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        frame = StartPage(container, self)

        self.frames[StartPage] = frame

        frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

app = MainApp()
app.mainloop()

方法

解决此问题的最佳方法很可能是制作一个 base_frame class,其中包含图像和 topleft_label、"Welcome - Login Screen"。这意味着 StartPage object 可以继承 base_frame class 的背景图像。


代码

import tkinter as tk

LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1366


class MainApp():
    def __init__(self, master):
        self.master = master
        self.master.title("Sales System") 
        self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT)) 

        self.frames = {}

        start_page = StartPage(master)

        self.frames[StartPage] = start_page

        start_page.grid(row=0, column=0, sticky="nsew")
        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


class base_frame(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(master, *args, **kwargs)

        b_image = tk.PhotoImage(file='background.png')
        b_label = tk.Label(self, image=b_image)
        b_label.image = b_image
        b_label.place(x=0, y=0, relwidth=1, relheight=1)

        topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
        topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')

class StartPage(base_frame):

    def __init__(self, parent):
        super().__init__(self, parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

def main():
    root = tk.Tk() # MainApp()
    main_app = MainApp(root)
    root.mainloop()

if __name__ == '__main__':
    main()

崩溃

开始代码

使这个class系统运行的代码是这样的:

def main():
    root = tk.Tk() # MainApp()
    main_app = MainApp(root)
    root.mainloop()

if __name__ == '__main__':
    main()

英文行if __name__ == '__main__':也大致翻译为:If the program is 运行 and not imported。因此,如果程序是 运行 且未导入,则 运行 主要功能。

root = tk.Tk() 只是在根变量中创建一个 Tk window。

main_app = MainApp(root) 初始化 main_app object 其主人是根变量

root.mainloop() 启动 tkinter 循环。

MainApp Class

MainApp Class 首先将其标题设置为 "Sales System" 并将几何图形重置为在 HEIGHT & WIDTH:

中定义的值
        self.master = master
        self.master.title("Sales System") 
        self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT)) 

然后 self.frames 字典和 start_page 被初始化并且 start_page 被放置在 self.frames:

        self.frames = {}

        start_page = StartPage(master)

        self.frames[StartPage] = start_page

然后设置start_page来填充整个window:

        start_page.grid(row=0, column=0, sticky="nsew")
        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)

然后我们显示第一页:

self.show_frame(StartPage)

然后创建 show_frame 函数

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

base_frame Class

前 3 行创建一个 class,其值与 tk.Frame object 相同,参数和关键字参数通过:

class base_frame(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(master, *args, **kwargs)

然后创建图像标签:

        b_image = tk.PhotoImage(file='background.png')
        b_label = tk.Label(self, image=b_image)
        b_label.image = b_image
        b_label.place(x=0, y=0, relwidth=1, relheight=1)

b_label.image = b_image 行用于确保图像由标签显示(从函数内加载时这是必需的)。

然后我们创建默认的topleft_label:

topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
        topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')

您可能希望更新此代码以便将来更改这些标签,只需将 topleft_label 替换为 self.topleft_label 并将 b_label 替换为 self.b_label

起始页Class

这个 class 与您之前创建的 class 没有太大区别:

class StartPage(base_frame):

    def __init__(self, parent):
        super().__init__(self, parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

唯一的区别是它不是继承自 tk.Frame,而是继承自 base_frame class。