我想创建5帧的tkinter网格布局。在替换Frame内容之前,它看起来就像我想要的那样。
self.Frame1 = tk.Frame(self.parent, bg="grey")
与
self.Frame1 = LeftUpperWindow(self.parent)
当我最大化窗口时,我看到LeftUpperWindow框架中的所有内容都搞乱了,布局不正确。一张图片胜过千言万语,所以我有这个
并希望有这个
import sys
import os
import Tkinter as tk
import ttk as ttk
class LeftUpperWindow(tk.Frame):
def __init__(self, master=None):
self.parent = master
tk.Frame.__init__(self, self.parent, bg='#ffffff', borderwidth=1, relief="sunken")
self.__create_layout()
def __create_layout(self):
self.parent.grid()
for r in range(3):
self.parent.rowconfigure(r, weight=1)
for c in range(2):
self.parent.columnconfigure(c, weight=1)
self.editArea = tk.Text(self.parent, wrap=tk.NONE, undo=True,
relief=tk.SUNKEN, borderwidth=5, highlightthickness=0, insertbackground="white")
self.editArea.config(font=('courier', 10, 'normal'))
self.editArea.configure(bg="black", fg="white")
self.editArea.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
self.scrollbarY = tk.Scrollbar(self.parent, orient=tk.VERTICAL)
self.scrollbarY.grid(row=0, column=1, sticky=(tk.N, tk.S), rowspan=2)
self.scrollbarX = tk.Scrollbar(self.parent, orient=tk.HORIZONTAL)
self.scrollbarX.grid(row=1, column=0, sticky=(tk.W, tk.E))
self.status = tk.Label(self.parent, text="Status label", bd=1, relief=tk.SUNKEN, anchor=tk.W, bg='lightgray')
self.status.grid(row=2, column=0, sticky=(tk.N, tk.S, tk.W, tk.E), columnspan=2)
def __config_window(self):
pass
def close_quit(self, event=None):
self.parent.destroy()
def dummy_func(self):
print("dummy")
pass
class MainWindow(tk.Frame):
def __init__(self, master=None):
self.parent = master
tk.Frame.__init__(self, self.parent, bg='#ffffff', borderwidth=1, relief="sunken")
self.__create_layout()
self.__create_menu()
self.__config_mainWindow()
def __create_layout(self):
self.parent.grid()
for r in range(6):
self.parent.rowconfigure(r, weight=1)
for c in range(10):
self.parent.columnconfigure(c, weight=1)
self.Frame1 = LeftUpperWindow(self.parent) #tk.Frame(self.parent, bg="grey")
self.Frame1.grid(row=0, column=0, rowspan=4, columnspan=8, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame2 = tk.Frame(self.parent, bg="blue")
self.Frame2.grid(row=0, column=8, rowspan=4, columnspan=2, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame3 = tk.Frame(self.parent, bg="green")
self.Frame3.grid(row=4, column=0, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame4 = tk.Frame(self.parent, bg="brown")
self.Frame4.grid(row=4, column=5, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame5 = tk.Frame(self.parent, bg="pink")
self.Frame5.grid(row=5, column=0, rowspan=1, columnspan=10, sticky=(tk.N, tk.S, tk.W, tk.E))
def close_quit(self, event=None):
self.parent.destroy()
def __config_mainWindow(self):
self.parent.config(menu=self.menubar)
def __create_menu(self):
self.menubar = tk.Menu(self.parent)
self.filemenu = tk.Menu(self.menubar, tearoff=0)
self.filemenu.add_command(label="Open", command=self.dummy_func)
self.filemenu.add_separator()
self.filemenu.add_command(label="Exit", command=self.close_quit)
self.menubar.add_cascade(label="File", menu=self.filemenu)
helpmenu = tk.Menu(self.menubar, tearoff=0)
helpmenu.add_command(label="About...", command=self.dummy_func)
self.menubar.add_cascade(label="Help", menu=helpmenu)
def dummy_func(self):
print("dummy")
pass
#
# MAIN
#
def main():
root = tk.Tk()
root.title("Frames")
root.geometry("550x300+525+300")
root.configure(background="#808080")
root.option_add("*font", ("Courier New", 9, "normal"))
window = MainWindow(master=root)
root.protocol("WM_DELETE_WINDOW", window.close_quit)
root.mainloop()
if __name__ == '__main__':
main()
答案 0 :(得分:3)
您的问题没有快速解决方法。您正在代码中执行多项操作来堆叠您的可能性,这使得调试代码变得非常困难。重写是最好的解决方案。
以下是我发现的问题,使问题比他们需要的更难,并且可以通过重写来解决。
首先,不要让小部件负责将自己置于其父级中。在您的情况下,通过让小部件将其父母置于其祖父母中,您将更进一步。这只是错误的做法。一个包含窗口应该负责布局它的孩子,而不再是
其次,尽可能多地将布局代码放在一起。通过"所有"我的意思是"所有对于给定的容器"。所以,例如,而不是:
x=Label(...)
x.grid(...)
y =Label(...)
y.grid(...)
......这样做:
x = Label(...)
y = Label(...)
x.grid(...)
y.grid(...)
这使得在代码中可视化您的布局变得更加容易。
第三,不要试图同时解决多个布局问题。一次解决一个问题。由于您发布了整个程序,我假设您对整个程序有问题,而不仅仅是左上角的小部件。当我运行你的代码时,我观察到调整大小的行为似乎对我不利,强化了这种信念。
第四,如果你创建一个像MainWindow这样设计用于包含其他小部件的类,那么所有其他小部件都是窗口的子节点,而不是父节点的子节点。
第五,作为一般经验法则,您只希望单行和单列与容器具有非零权重。这只是一个指导原则,因为有时您需要多个窗口小部件进行扩展或收缩。对于滚动条和状态标签,您通常不希望给它们额外的空间。您的代码中的部分问题在于您将所有内容都赋予了权重,因此为每个小部件分配了额外的空间。
解决方案一次只能处理一个部分。让它工作,然后继续下一部分。在你的情况下,我看到努力分为四个阶段。首先,创建并布置主窗口。接下来,添加作为主窗口的直接子项的窗口小部件。之后,为左上角窗口创建容器。最后,将小部件添加到左上角窗口。在每个阶段之后,请务必运行代码并验证一切正常。
第一步是从主窗口开始。让它看起来正确,并在调整主窗口大小时正常运行。当我运行你的代码时,当窗口变小时,底部和右侧窗口将消失,而当窗口很大时,底部框架会增长。我猜这不是正确的行为。无论如何,从你认为正确的行为开始,并在添加更多小部件之前使其工作。
从以下代码开始。验证当您调整窗口大小时,所有内容都会以您期望的方式扩展和收缩。请注意,我做了几个简单的更改。需要注意的主要事情是创建主窗口的函数负责使该窗口可见。我使用pack
,因为它是根窗口中唯一的小部件,这意味着我可以在一行中完成所有操作,而不必担心grid
的行和列权重。
import sys
import os
import Tkinter as tk
import ttk as ttk
class MainWindow(tk.Frame):
def __init__(self, master=None):
self.parent = master
tk.Frame.__init__(self, self.parent, bg='bisque', borderwidth=1, relief="sunken")
self.__create_layout()
def __create_layout(self):
pass
#
# MAIN
#
def main():
root = tk.Tk()
root.title("Frames")
root.geometry("550x300+525+300")
root.configure(background="#808080")
root.option_add("*font", ("Courier New", 9, "normal"))
window = MainWindow(master=root)
window.pack(side="top", fill="both", expand=True)
root.mainloop()
if __name__ == '__main__':
main()
一旦MainWindow
shell表现正常,就可以添加更多小部件了。看起来你有五个框架,但其中一个是自定义类。现在,我们将使用常规框架来保持简单。为每个人提供一种颜色很好,这是在构建窗口时可视化布局的好方法。
将__create_layout
修改为如下所示。请注意两个重要更改:每个小部件都是self
而不是self.parent
的子级,并且我已将所有布局代码组合在一起。
调整大小的行为让我感到满意,但我并不确切地知道你的意图。对我来说,让绿色,红色和粉红色的框架按照他们的方式调整大小似乎很奇怪,尽管这可能是你想要的。无论如何,现在是时候做对了。
def __create_layout(self):
self.Frame1 = tk.Frame(self, bg="grey")
self.Frame2 = tk.Frame(self, bg="blue")
self.Frame3 = tk.Frame(self, bg="green")
self.Frame4 = tk.Frame(self, bg="brown")
self.Frame5 = tk.Frame(self, bg="pink")
self.Frame1.grid(row=0, column=0, rowspan=4, columnspan=8, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame2.grid(row=0, column=8, rowspan=4, columnspan=2, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame3.grid(row=4, column=0, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame4.grid(row=4, column=5, rowspan=2, columnspan=5, sticky=(tk.N, tk.S, tk.W, tk.E))
self.Frame5.grid(row=5, column=0, rowspan=1, columnspan=10, sticky=(tk.N, tk.S, tk.W, tk.E))
for r in range(6):
self.rowconfigure(r, weight=1)
for c in range(10):
self.columnconfigure(c, weight=1)
接下来,让我们定义LeftUpperWindow
类,并确保我们没有破坏任何东西。为类添加一个存根,给窗口一个不同的颜色,并确保窗口在出现时和调整大小时仍然看起来正常。
class LeftUpperWindow(tk.Frame):
def __init__(self, master=None):
self.parent = master
tk.Frame.__init__(self, self.parent, bg='bisque', borderwidth=1, relief="sunken")
self.__create_layout()
def __create_layout(self):
pass
请记住修改MainWindow.__create_layout
以创建此类的实例而不是框架:
self.frame1 = LeftUpperWindow(self)
最后,是时候在LeftUpperWindow
中添加小部件了。就像我们在MainWindow
中所做的那样,小部件都是self
的子节点,小部件创建和小部件布局在不同的组中完成。此外,通常最好只给出单行和单列非零权重。这通常是文本或画布小部件所在的行和列。
当然,你可以做你想做的事。请注意,因为您在原始代码中为每个行和列赋予了权重,这有助于窗口小部件之间的所有空间。
此外,由于您为GUI提供了明确的大小(通过root.geometry(...)
),因此您希望为文本小部件提供较小的尺寸。否则,默认宽度和高度将推出其他小部件,因为tkinter尝试为每个小部件提供其默认大小。由于您要限制整个窗口大小,因此您希望文本小部件尽可能小,然后让grid
展开它以填充它已被赋予的区域。
这里__create_layout
应该是什么样的:
def __create_layout(self):
self.editArea = tk.Text(self, wrap=tk.NONE, undo=True,
width=1, height=1,
relief=tk.SUNKEN, borderwidth=5,
highlightthickness=0, insertbackground="white")
self.editArea.config(font=('courier', 10, 'normal'))
self.editArea.configure(bg="black", fg="white")
self.scrollbarY = tk.Scrollbar(self, orient=tk.VERTICAL)
self.scrollbarX = tk.Scrollbar(self, orient=tk.HORIZONTAL)
self.status = tk.Label(self, text="Status label", bd=1, relief=tk.SUNKEN,
anchor=tk.W, bg='lightgray')
self.editArea.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.W, tk.E))
self.scrollbarY.grid(row=0, column=1, sticky=(tk.N, tk.S), rowspan=2)
self.scrollbarX.grid(row=1, column=0, sticky=(tk.W, tk.E))
self.status.grid(row=2, column=0, sticky=(tk.N, tk.S, tk.W, tk.E), columnspan=2)
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)