创建布局时使用 pack 的具体问题
Specific issue using pack while creating a layout
我必须使用 tkinter 库来创建 GUI。
我有这个代码:
# -*- coding: UTF-8 -*-
import tkinter as tk
class Application(tk.Frame):
resx=1600
resy=900
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack(fill="both", expand=1)
self.createWidgets()
master.minsize(self.resx, self.resy)
master.maxsize(self.resx, self.resy)
def createWidgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Create new window"
self.hi_there["command"] = self.PlayMode
self.hi_there.pack(side="top")
def ShowMenu(self, master):
print("Here I need DELETE master, in my case PlayM")
def PlayMode(self):
PlayM = tk.Tk()
PlayM.minsize(self.resx, self.resy)
PlayM.maxsize(self.resx, self.resy)
PlayM.title("Game")
bf= tk.Frame(PlayM, bg="blue")
bf.pack(side="bottom", fill=tk.X, expand = 1)
lbTEST=tk.Label(bf)
lbTEST["text"] = "TESTING"
lbTEST.pack()
mf = tk.Frame(PlayM,bg="red")
mf.pack(side="right", fill=tk.Y, expand=1)
self.LogOut = tk.Button(mf)
self.LogOut["text"] = "LOGOUT"
self.LogOut.pack()
self.LogOut["command"] = self.ShowMenu(PlayM)
root = tk.Tk()
app = Application(master=root)
app.master.title("Useless think")
app.mainloop()
我需要这样的图片:
我不知道为什么我的代码不起作用。当我打包 bf
(底部框架)并设置 side = "bottom"
时,它出现在屏幕中间。为什么?
当我打包 mf
(菜单框架)
时与 side = "right"
相同
我还有一个问题。关于注销按钮。我设置命令的方法 "ShowMenu"
。
当我 运行 我的代码时,这个方法只自动启动一次,但是当我点击按钮时没有任何反应。为什么?
你使用 pack 方法而不是 grid 有什么具体原因吗?
您可以像这样配置您的应用程序框架:
self.grid_rowconfigure(0, weight=1) #make the first "upper" row expand
self.grid_rowconfigure(1, weight=0) #leave the second "lower" row and do not expand it
self.grid_columnconfigure(0, weight=0) # first column, do not expand
self.grid_columnconfigure(1, weight=1) # second columnd, DO expand
self.grid_columnconfigure(0, weight=0) # third column, do not expand
在您的 mainframe/application class 上,然后致电:
bf.grid(row=1, column=0, columnspan=3, sticky=tk.NW+tk.SE) # span over three columns
lf.grid(row=0, column=0, sticky=tk.NW+tk.SE) # default is to span over one column
rf.grid(row=0, column=2, sticky=tk.NW+tk.SE)
编辑
非常抱歉,我忘记提到注销按钮了。
您在绑定时调用事件处理程序,因此它将在那里执行。
如果您想让它传递值,请使用:
- command=lambda parent=PlayM: self.ShowMenu(parent)
- 使用 class 对象在创建时存储你的父引用
self._Parent = PlayM
并在 ShowMenu 中使用它
我个人更喜欢为单个值存储对象。如果你有很多 windows 要销毁,我会使用 lambda。
首先,您的代码存在严重缺陷。您不应创建多个 Tk
实例。如果您需要创建额外的 windows,请创建 Toplevel
.
的实例
When I pack my bf (bottom frame) and set side = "bottom", but it appears in the middle of the screen. Why?
您将 mf
和 mf
的 expand
设置为 1
,因此每个人最终都会占用 [=] 中可用 space 的一半51=]。如果您只是将 expand
设置为 0(零)或将 bf
设置为 False
,它只会占用必要的 space。
bf.pack(side="bottom", fill=tk.X, expand = 0)
作为一般规则,您应该只在单个小部件("hero" 小部件)上为 expand
设置真值,除非您希望将额外的 space 平均分配给小部件。
When I run my code, this method is started automatically only once, but when I click to button nothing happens. Why?
因为您要告诉 运行。看看这段代码:
self.LogOut["command"] = self.ShowMenu(PlayM)
和这段代码完全一样:
result = self.ShowMenu(PlayM)
self.logOut["command"] = result
看到问题了吗?
command
属性需要对函数的 引用。粗略翻译一下,就是不能用()
。如果您需要向命令传递参数,典型的解决方案是使用 functools.partial
或 lambda
创建对匿名函数的引用,该函数将使用参数调用真实函数:
self.logOut["command"] = lambda arg=PlayM: self.ShowMenu(arg)
除了Bryan Oakley已经提到的问题和R4PH43L使用grid
给出的解决方案,这里有一个可能仅使用 pack
的布局解决方案。
这个想法是,通过使用 side="left"
(或 side="right"
)然后使用 side="top"
(或 side="bottom"
)并不像您期望的那样工作。
在一个框架内,您应该只使用 side
的值(在同一框架中打包小部件时),这些值可以是垂直的("top"
或 "bottom"
)或水平的("right"
或 "left"
),但不是 两者。因此,要仅使用 pack
完成像您这样的布局,您需要额外的框架!
# -*- coding: UTF-8 -*-
import tkinter as tk
class Application(tk.Frame):
resx=400
resy=200
def __init__(self, master=None):
tk.Frame.__init__(self, master, bg="red")
self.pack(fill="both", expand=1)
self.create_widgets()
master.geometry("400x200+100+500")
def create_widgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Create new window"
self.hi_there["command"] = self.play_mode
self.hi_there.pack(side="top")
def show_menu(self, master):
print("Here I need DELETE master, in my case play_m")
def play_mode(self):
# Using a Toplevel instead of a Tk
# You should have just one Tk in your app
play_m = tk.Toplevel()
play_m.geometry("400x200+100+500")
play_m.title("Game")
top_frame = tk.Frame(play_m, bg="blue")
top_frame.pack(side="top", fill="both", expand=True)
left_top_frame = tk.Frame(top_frame, bg="white")
left_top_frame_label = tk.Label(left_top_frame, text="left top frame")
left_top_frame_label.pack()
left_top_frame.pack(side="left", fill="y")
middle_top_frame = tk.Frame(top_frame, bg="black")
middle_top_frame_button = tk.Button(middle_top_frame, text="Logout", command=play_m.destroy)
middle_top_frame_button.pack()
middle_top_frame.pack(side="left", fill="both", expand=True)
right_top_frame = tk.Frame(top_frame, bg="white")
right_top_frame_label = tk.Label(right_top_frame, text="right top frame")
right_top_frame_label.pack()
right_top_frame.pack(side="right", fill="y")
bottom_frame = tk.Frame(play_m, bg="yellow")
bottom_frame_label = tk.Label(bottom_frame, text="bottom frame")
bottom_frame_label.pack()
bottom_frame.pack(side="top", fill="both")
root = tk.Tk()
app = Application(master=root)
app.master.title("Useless think")
app.mainloop()
这是 Tk
window 在 OS X (Sierra) 上的主要结果:
第二个顶层
为了便于说明,我稍微更改了尺寸。我还重命名了使用 _
和小写字母的方法。
我必须使用 tkinter 库来创建 GUI。
我有这个代码:
# -*- coding: UTF-8 -*-
import tkinter as tk
class Application(tk.Frame):
resx=1600
resy=900
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack(fill="both", expand=1)
self.createWidgets()
master.minsize(self.resx, self.resy)
master.maxsize(self.resx, self.resy)
def createWidgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Create new window"
self.hi_there["command"] = self.PlayMode
self.hi_there.pack(side="top")
def ShowMenu(self, master):
print("Here I need DELETE master, in my case PlayM")
def PlayMode(self):
PlayM = tk.Tk()
PlayM.minsize(self.resx, self.resy)
PlayM.maxsize(self.resx, self.resy)
PlayM.title("Game")
bf= tk.Frame(PlayM, bg="blue")
bf.pack(side="bottom", fill=tk.X, expand = 1)
lbTEST=tk.Label(bf)
lbTEST["text"] = "TESTING"
lbTEST.pack()
mf = tk.Frame(PlayM,bg="red")
mf.pack(side="right", fill=tk.Y, expand=1)
self.LogOut = tk.Button(mf)
self.LogOut["text"] = "LOGOUT"
self.LogOut.pack()
self.LogOut["command"] = self.ShowMenu(PlayM)
root = tk.Tk()
app = Application(master=root)
app.master.title("Useless think")
app.mainloop()
我需要这样的图片:
我不知道为什么我的代码不起作用。当我打包 bf
(底部框架)并设置 side = "bottom"
时,它出现在屏幕中间。为什么?
当我打包 mf
(菜单框架)
side = "right"
相同
我还有一个问题。关于注销按钮。我设置命令的方法 "ShowMenu"
。
当我 运行 我的代码时,这个方法只自动启动一次,但是当我点击按钮时没有任何反应。为什么?
你使用 pack 方法而不是 grid 有什么具体原因吗?
您可以像这样配置您的应用程序框架:
self.grid_rowconfigure(0, weight=1) #make the first "upper" row expand
self.grid_rowconfigure(1, weight=0) #leave the second "lower" row and do not expand it
self.grid_columnconfigure(0, weight=0) # first column, do not expand
self.grid_columnconfigure(1, weight=1) # second columnd, DO expand
self.grid_columnconfigure(0, weight=0) # third column, do not expand
在您的 mainframe/application class 上,然后致电:
bf.grid(row=1, column=0, columnspan=3, sticky=tk.NW+tk.SE) # span over three columns
lf.grid(row=0, column=0, sticky=tk.NW+tk.SE) # default is to span over one column
rf.grid(row=0, column=2, sticky=tk.NW+tk.SE)
编辑
非常抱歉,我忘记提到注销按钮了。 您在绑定时调用事件处理程序,因此它将在那里执行。
如果您想让它传递值,请使用:
- command=lambda parent=PlayM: self.ShowMenu(parent)
- 使用 class 对象在创建时存储你的父引用
self._Parent = PlayM
并在 ShowMenu 中使用它
我个人更喜欢为单个值存储对象。如果你有很多 windows 要销毁,我会使用 lambda。
首先,您的代码存在严重缺陷。您不应创建多个 Tk
实例。如果您需要创建额外的 windows,请创建 Toplevel
.
When I pack my bf (bottom frame) and set side = "bottom", but it appears in the middle of the screen. Why?
您将 mf
和 mf
的 expand
设置为 1
,因此每个人最终都会占用 [=] 中可用 space 的一半51=]。如果您只是将 expand
设置为 0(零)或将 bf
设置为 False
,它只会占用必要的 space。
bf.pack(side="bottom", fill=tk.X, expand = 0)
作为一般规则,您应该只在单个小部件("hero" 小部件)上为 expand
设置真值,除非您希望将额外的 space 平均分配给小部件。
When I run my code, this method is started automatically only once, but when I click to button nothing happens. Why?
因为您要告诉 运行。看看这段代码:
self.LogOut["command"] = self.ShowMenu(PlayM)
和这段代码完全一样:
result = self.ShowMenu(PlayM)
self.logOut["command"] = result
看到问题了吗?
command
属性需要对函数的 引用。粗略翻译一下,就是不能用()
。如果您需要向命令传递参数,典型的解决方案是使用 functools.partial
或 lambda
创建对匿名函数的引用,该函数将使用参数调用真实函数:
self.logOut["command"] = lambda arg=PlayM: self.ShowMenu(arg)
除了Bryan Oakley已经提到的问题和R4PH43L使用grid
给出的解决方案,这里有一个可能仅使用 pack
的布局解决方案。
这个想法是,通过使用 side="left"
(或 side="right"
)然后使用 side="top"
(或 side="bottom"
)并不像您期望的那样工作。
在一个框架内,您应该只使用 side
的值(在同一框架中打包小部件时),这些值可以是垂直的("top"
或 "bottom"
)或水平的("right"
或 "left"
),但不是 两者。因此,要仅使用 pack
完成像您这样的布局,您需要额外的框架!
# -*- coding: UTF-8 -*-
import tkinter as tk
class Application(tk.Frame):
resx=400
resy=200
def __init__(self, master=None):
tk.Frame.__init__(self, master, bg="red")
self.pack(fill="both", expand=1)
self.create_widgets()
master.geometry("400x200+100+500")
def create_widgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Create new window"
self.hi_there["command"] = self.play_mode
self.hi_there.pack(side="top")
def show_menu(self, master):
print("Here I need DELETE master, in my case play_m")
def play_mode(self):
# Using a Toplevel instead of a Tk
# You should have just one Tk in your app
play_m = tk.Toplevel()
play_m.geometry("400x200+100+500")
play_m.title("Game")
top_frame = tk.Frame(play_m, bg="blue")
top_frame.pack(side="top", fill="both", expand=True)
left_top_frame = tk.Frame(top_frame, bg="white")
left_top_frame_label = tk.Label(left_top_frame, text="left top frame")
left_top_frame_label.pack()
left_top_frame.pack(side="left", fill="y")
middle_top_frame = tk.Frame(top_frame, bg="black")
middle_top_frame_button = tk.Button(middle_top_frame, text="Logout", command=play_m.destroy)
middle_top_frame_button.pack()
middle_top_frame.pack(side="left", fill="both", expand=True)
right_top_frame = tk.Frame(top_frame, bg="white")
right_top_frame_label = tk.Label(right_top_frame, text="right top frame")
right_top_frame_label.pack()
right_top_frame.pack(side="right", fill="y")
bottom_frame = tk.Frame(play_m, bg="yellow")
bottom_frame_label = tk.Label(bottom_frame, text="bottom frame")
bottom_frame_label.pack()
bottom_frame.pack(side="top", fill="both")
root = tk.Tk()
app = Application(master=root)
app.master.title("Useless think")
app.mainloop()
这是 Tk
window 在 OS X (Sierra) 上的主要结果:
第二个顶层
为了便于说明,我稍微更改了尺寸。我还重命名了使用 _
和小写字母的方法。