首页 文章

Python Tkinter面向对象 - 以多个框架为中心

提问于
浏览
2

所以我在Python中编写面向对象的程序,并使用Tkinter构建GUI . 我是面向对象和Tkinter的新手,所以我一直在youtube,effbot.org,stackoverflow和zetcode.com上使用Sentdex视频来帮助我 .

这是我的程序,我已经删除了很多,所以它更短,更容易理解 . 它以全屏模式启动并使框架居中 . 然后我单击登录按钮,然后引发下一帧,但是这一帧不会居中,尽管它位于由权重= 1的单元格包围的网格中间 .

import tkinter as tk
from tkinter import ttk

class Program(tk.Tk):        
    def __init__(self, *args, **kwargs):   
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(2, weight=1)
        container.grid_columnconfigure(2, weight=1)

        self.frames = {}
        frame = Login(container, self)
        self.frames[Login] = frame

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

        for F in (Login, AdminHome):

            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row = 1, column = 1, sticky = "nsew")

        self.show_frame(Login)

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

class Login(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        name = tk.Label(self, text = "Program")
        name.grid(row=0, columnspan=5, sticky="W"+"E")

        username = tk.Label(self, text="Username: ")
        username.grid(row=1, columnspan=2, sticky="W")

        user = ttk.Entry(self, text ="", width=45)
        user.grid(row=1, column=2 ,columnspan=3, sticky="w")

        password = tk.Label(self, text="Password: ")
        password.grid(row=2, columnspan=2, sticky="W")

        passentry = ttk.Entry(self, text ="", width=45)
        passentry.grid(row=2, column=2 ,columnspan=3, sticky="W")

        loginb = ttk.Button(self, text = "Login", command = lambda: controller.show_frame(AdminHome))
        loginb.grid(row=3, columnspan=5, sticky="W"+"E")

class AdminHome(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        name = tk.Label(self, text = "Admin Home")
        name.grid(row=0, sticky="W")

        name = tk.Label(self, text = "FirstName + LastName")
        name.grid(row=0, column=5 ,sticky="E")

        update = ttk.Button(self, text = "Update Online", command = lambda: controller.show_frame(AdminHome))
        update.grid(row=1, columnspan=6, sticky="W"+"E")

        fetch = ttk.Button(self, text = "Fetch Data", command = lambda: controller.show_frame(AdminHome))
        fetch.grid(row=2, columnspan=6, sticky="W"+"E")

        a = ttk.Button(self, text = "a", command = lambda: controller.show_frame(AdminHome))
        a.grid(row=3, columnspan=2, sticky="W"+"E")

        b = ttk.Button(self, text = "b", command = lambda: controller.show_frame(AdminHome))
        b.grid(row=3, column=2, columnspan=2, sticky="W"+"E")

        c = ttk.Button(self, text = "c", command = lambda: controller.show_frame(AdminHome))
        c.grid(row=3, column=4, columnspan=2, sticky="W"+"E")

        edit = ttk.Button(self, text = "Edit Details", command = lambda: controller.show_frame(AdminHome))
        edit.grid(row=4, columnspan=6, sticky="W"+"E")

app = Program()
app.state('zoomed')
app.mainloop()

Login Screen before progress bars are added

当我将以下代码添加到AdminHome类时,问题相反,登录屏幕停止居中但管理员主屏幕变为居中 .

uip = tk.Label(self, text="Updating in Progress ")
    uip.grid(row=5, sticky="W")

    updatebar = ttk.Progressbar(self,orient ="horizontal",length = 200, mode ="determinate")
    updatebar.grid(row=5, column=1, sticky="W"+"E")
    updatebar["maximum"] = 100
    updatebar["value"] = 50


    fip = tk.Label(self, text="Fetching in Progress ")
    fip.grid(row=5, column=2, sticky="W")

    fetchbar = ttk.Progressbar(self,orient ="horizontal",length = 200, mode ="determinate")
    fetchbar.grid(row=5, column=3, sticky="W"+"E")
    fetchbar["maximum"] = 100
    fetchbar["value"] = 50

Login Screen after progress bars are added

有人能告诉我为什么会这样,以及我如何解决它 . 如果我改变这些框架中小部件的大小以及我添加到程序中的所有其他框架,我还需要解决方案 .

1 回答

  • 0

    问题不在于容器中心,而是以管理框架为中心 . 通过赋予 AdminHome 框架独特的颜色,您可以非常轻松地看到这一点 . 执行此操作时,您将看到 AdminHome 框架在窗口中保持居中 .

    您复制的代码是专门为单个“页面”对象填充它们所在的单元格而设计的 . 代码只能以这种方式工作,因为小部件全部堆叠在一起 . 它们需要具有相同的尺寸,否则您将看到较小的框架后面的较大框架 .

    由于您不太了解代码的工作原理,我的建议是不要尝试更改代码 . 而不是试图使页面居中,而是专注于使页面中的数据居中 . 每个页面都设计为完全独立,因此无论您在该框架内执行什么操作都不会影响任何其他窗口小部件 .

    使每个页面中的内容居中的最简单的解决方案是使用另一个帧 . 将所有小部件放在该框架中,然后将该框架居中 . 您实际上并不需要这样做,您也可以使用您之前尝试使用的相同技巧,方法是在页面内的所有小部件周围添加“加权”行和列 .

    以下是一个完整的工作示例 . 这不是解决问题的唯一方法,甚至可能不是最好的方法 . 请注意,由于使用 place ,您必须为整个窗口指定一个大小(或设置 zoomed 属性,就像您正在做的那样) . 这是因为使用 place 不会强制窗口适合其内容 .

    要寻找的重要一点是在每个页面中使用 innerFrame . 这是集中的事情 .

    import tkinter as tk
    from tkinter import ttk
    
    class Program(tk.Tk):        
        def __init__(self, *args, **kwargs):   
            tk.Tk.__init__(self, *args, **kwargs)
    
            container = tk.Frame(self)
            container.pack(side="top", fill="both", expand=True)
            container.grid_rowconfigure(0, weight=1)
            container.grid_columnconfigure(0, weight=1)
    
            self.frames = {}
            for F in (Login, AdminHome):
    
                frame = F(container, self)
                self.frames[F] = frame
                frame.grid(row = 0, column = 0, sticky = "nsew")
    
            self.show_frame(Login)
    
        def show_frame(self,cont):
            frame = self.frames[cont]
            frame.tkraise()
    
    class Login(tk.Frame):
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
    
            innerFrame = tk.Frame(self)
            innerFrame.place(relx=.5, rely=.5, anchor="c")
    
            name = tk.Label(innerFrame, text = "Program")
            name.grid(row=0, columnspan=5, sticky="W"+"E")
    
            username = tk.Label(innerFrame, text="Username: ")
            username.grid(row=1, columnspan=2, sticky="W")
    
            user = ttk.Entry(innerFrame, text ="", width=45)
            user.grid(row=1, column=2 ,columnspan=3, sticky="w")
    
            password = tk.Label(innerFrame, text="Password: ")
            password.grid(row=2, columnspan=2, sticky="W")
    
            passentry = ttk.Entry(innerFrame, text ="", width=45)
            passentry.grid(row=2, column=2 ,columnspan=3, sticky="W")
    
            loginb = ttk.Button(innerFrame, text = "Login", command = lambda: controller.show_frame(AdminHome))
            loginb.grid(row=3, columnspan=5, sticky="W"+"E")
    
    class AdminHome(tk.Frame):
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
    
            innerFrame = tk.Frame(self)
            innerFrame.place(relx=.5, rely=.5, anchor="c")
    
            name = tk.Label(innerFrame, text = "Admin Home")
            name.grid(row=0, sticky="W")
    
            name = tk.Label(innerFrame, text = "FirstName + LastName")
            name.grid(row=0, column=5 ,sticky="E")
    
            update = ttk.Button(innerFrame, text = "Update Online", command = lambda: controller.show_frame(AdminHome))
            update.grid(row=1, columnspan=6, sticky="W"+"E")
    
            fetch = ttk.Button(innerFrame, text = "Fetch Data", command = lambda: controller.show_frame(AdminHome))
            fetch.grid(row=2, columnspan=6, sticky="W"+"E")
    
            a = ttk.Button(innerFrame, text = "a", command = lambda: controller.show_frame(AdminHome))
            a.grid(row=3, columnspan=2, sticky="W"+"E")
    
            b = ttk.Button(innerFrame, text = "b", command = lambda: controller.show_frame(AdminHome))
            b.grid(row=3, column=2, columnspan=2, sticky="W"+"E")
    
            c = ttk.Button(innerFrame, text = "c", command = lambda: controller.show_frame(AdminHome))
            c.grid(row=3, column=4, columnspan=2, sticky="W"+"E")
    
            edit = ttk.Button(innerFrame, text = "Edit Details", command = lambda: controller.show_frame(AdminHome))
            edit.grid(row=4, columnspan=6, sticky="W"+"E")
    
    app = Program()
    app.state('zoomed')
    app.mainloop()
    

相关问题