到目前为止,这个程序的功能是明智的,所以这不是我的问题。我的问题与具有多个框架的小部件的对齐方式有关。如果我将一个框架上的小部件比其他框架更宽,那么它将基于最宽的框架而不是每个单独的框架将所有框架对中。现在这段代码中最宽的框架是' 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()
答案 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)
布局小部件需要有条不紊的方法。它有助于暂时为每个帧提供不同的颜色,以便您可以看到哪些帧正在增长或缩小以适合其内容和/或其父项。通常,这足以看出问题是框架,框架中的内容,还是框架中的内容。
此外,如果不提供明确的参数,您几乎不应该使用pack
,place
或grid
。当您使用grid
时,请始终至少为一行和一列提供权重。