影响另一帧对齐的一帧上的tkinter小部件

时间:2016-10-07 19:04:46

标签: python tkinter alignment

到目前为止,这个程序的功能是明智的,所以这不是我的问题。我的问题与具有多个框架的小部件的对齐方式有关。如果我将一个框架上的小部件比其他框架更宽,那么它将基于最宽的框架而不是每个单独的框架将所有框架对中。现在这段代码中最宽的框架是' ChangePasswordPage'因为它几乎总是使用长字符串作为标签;这会导致所有其他帧向左移动。如果我删除' sticky =" nsew"'从frame.grid(column = 0,row = 0,sticky =" nsew")它将正确对齐所有内容,但框架不会向外填充,这样你就可以看到彼此背后的其他框架。

我不知道如何解决这个问题并希望得到一些帮助。我一直在尝试不同的方法,例如卸载每个小部件,然后重新加载它,但也有错误。任何帮助将受到高度赞赏。

这是我的精简代码:

import tkinter as tk
from tkinter import ttk, messagebox

class CCTV(tk.Tk):

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

        container = tk.Frame(self)
        container.pack()
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (LoginPage, ChangePasswordPage):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(column=0, row=0, sticky="nsew")

        self.creatingAccount()

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

    def creatingAccount(self):
        self.show_frame(LoginPage)



class LoginPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.createView()

    def createView(self):
        self.labelPassword = ttk.Label(self, text="Password")
        self.entryPassword = ttk.Entry(self, show = "*")
        self.buttonLogin = ttk.Button(self, text="Login", command=lambda: self.controller.show_frame(ChangePasswordPage))

        self.labelPassword.grid(row=2, column=3, sticky="w")
        self.entryPassword.grid(row=2, column=4, sticky="e")
        self.buttonLogin.grid(row=3, columnspan=6, pady=10)


class ChangePasswordPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.createView()

    def createView(self):
        self.labelSecurityQuestion = ttk.Label(self, text="A very very very very very very very very very very long string")
        self.entrySecurityQuestion = ttk.Entry(self)
        self.buttonCreateAccount = ttk.Button(self, text="Change Password", command=lambda: self.controller.show_frame(LoginPage))

        self.labelSecurityQuestion.grid(row=3, column=0, sticky="w")
        self.entrySecurityQuestion.grid(row=3, column=1, sticky="e")
        self.buttonCreateAccount.grid(row=5, columnspan=2, pady=10)


app = CCTV()
app.geometry("800x600")
app.mainloop()

1 个答案:

答案 0 :(得分:2)

通常有很多方法可以解决布局问题。这完全取决于您实际想要做什么,您正在使用的实际小部件,以及您希望小部件在其包含的窗口或框架发生变化时的反应。

使用grid时,默认情况下,它只为小部件提供所需的空间。包含小部件中的任何额外空间都将不使用。如果您希望grid使用所有可用空间,您必须告诉它如何通过提供行和列来分配额外空间" weight"。您没有这样做,因此没有使用额外的空间,因此,您的小部件不会居中。

根据经验,对于使用网格的任何容器(通常是框架),您必须为至少一行和一列赋予权重。如果您有画布或文本小部件,通常它所在的行和列是您要获取未分配空间的行和列。如果您有要增长和缩小的条目小部件,则通常会对包含条目小部件的列赋予权重。通常,您希望为多个行和/或列提供额外的空间,但有时候您希望所有内容都居中,并且沿着边缘分配额外的空间。

在您的具体情况下,要将密码屏幕中的所有内容置于中心,有几种解决方案。我会详细说明一对。

仅使用网格,并将所有小部件直接放在页面上

当您想要在一个框架中完全排列所有小部件并使用grid进行管理时,如果您希望窗口中的所有内容都处于中心位置,则可以为内容周围的行和列提供所有权重

这是一个例子。请注意,小部件位于第1行和第2行,第1列和第2列,所有额外空间都被赋予第0行和第3行以及第0列和第3列。

def createView(self):
    ...
    self.labelPassword.grid(row=1, column=1, sticky="e")
    self.entryPassword.grid(row=1, column=2, sticky="ew")
    self.buttonLogin.grid(row=2, column=1, columnspan=2)

    self.grid_rowconfigure(0, weight=1)
    self.grid_rowconfigure(3, weight=1)
    self.grid_columnconfigure(0, weight=1)
    self.grid_columnconfigure(3, weight=1)

使用嵌套框架

另一种方法是将小部件放入一个完全适合其内容的内框架中。当你这样做时,你只需要担心将一帧放在"页面中#34;因为,当你使框架居中时,按照定义,框架中的所有东西也将相对于整个窗口居中。

当你这样做时,你可以不必担心行和列权重,因为你希望内部框架缩小以适应内容,因此不必担心未分配的空间。但是,我个人认为始终至少提供一行和一列权重是件好事。

这是使用内框技术的一个例子。注意窗口小部件是如何放置在内部框架而不是self中,而内部框架使用pack而没有选项导致它在其父级顶部居中。您也可以使用place,如果您希望密码提示也垂直居中,这将非常方便。

def createView(self):
    inner_frame = tk.Frame(self)
    inner_frame.pack(side="top", fill="none")

    self.labelPassword = ttk.Label(inner_frame, text="Password")
    self.entryPassword = ttk.Entry(inner_frame, show = "*")
    self.buttonLogin = ttk.Button(inner_frame, text="Login", command=lambda: self.controller.show_frame(ChangePasswordPage))

    self.labelPassword.grid(row=1, column=1, sticky="e")
    self.entryPassword.grid(row=1, column=2, sticky="ew")
    self.buttonLogin.grid(row=2, column=1, columnspan=2)

摘要

布局小部件需要有条不紊的方法。它有助于暂时为每个帧提供不同的颜色,以便您可以看到哪些帧正在增长或缩小以适合其内容和/或其父项。通常,这足以看出问题是框架,框架中的内容,还是框架中的内容。

此外,如果不提供明确的参数,您几乎不应该使用packplacegrid。当您使用grid时,请始终至少为一行和一列提供权重。