在本程序中, 我们来讨论几个pack()用于布局的参数.
* side
* fill
* expand
* anchor
这个程序与本系列的其他程序不同. 它不需要你通过读源码来明白代码实现了哪些特性. 你只需要运行这个程序.
本程序的目的在于向你展示一下这些参数的不同效果. 此函数可以让你组合不同的pack参数来查看实际的效果.
*关于pack参数的潜在含义*
为了明白我们是如何控制容器中的控件的, 我们就要明白pack布局管理使用了一种被称为"洞"的排列模型. 它将每个容器看作是一个洞, 我们将控件塞进洞里.
在讨论容器中的控件定位前, 有几个概念有必要知道:
* 未分配的空间(它就是洞)
* 分配但没使用的空间
* 分配并使用了的空间
当你pack一个控件时, 比如一个按钮, 它问题被塞到洞的四个边上去. "side"参数来指定塞到哪条边上. 比如, 如果我们指定"side=LEFT", 则控件会被塞到(定位到)洞的最左边.
当一个控件被塞进来后, 它就被分配了一整条边, 即使它用不了那么多. 想象一下我们将一个小按钮X塞到容器的最左边上, 会如下图所示:
-------------------
claimed but | | |
unused -----> | | cavity |
| | (unclaimed) |
|___| |
claimed and | | |
used -------> | X | |
|___| |
| | |
claimed but | | |
unused -----> | | |
| | |
-------------------
这个洞(未分配的区域)现在就在控件的右边. 控件X分配到了整个左边, 一个足够容纳它的长条. 但因为控件X太小, 所以它实际上不会用掉所有分配到的空间. 它只用掉足够显示它的一部分空间.
如你所见, 当控件X需要显示自身时, 它就会申请足够大的空间. 如果我们指定了"expand=YES"参数, 那么它就会申请所有可用的区域. 洞中就不会再有剩余的空间了. 注意 这不是说控件X会*用掉*整个区域. 它仍然只会用到它所需要的一小部分空间.
如果一个控件申请到了多于它所能用的空间, 那么它将会:
* 它会因在未分配空间的某个角落
* 它会增长到填充满所有未分配的区域
如果我们想让它填充整个未分配的区域, 我们就要用到"fill"参数, 它指定了控件如何填充未使用的区域, 还有朝哪个方向进行填充.
* "fill=NONE" 表示不进行填充
* "fill=X" 沿X轴填充
* "fill=Y" 沿Y轴填充
* "fill=BOTH" 沿两个方向填充
如果我们想让它固定在未分配区域的某个位置上, 我们可以使用"anchor"参数, 它指定了控件在它分配到的区域中所呆的位置. anchor参数的取值很像罗盘. "N"表示"北"(也就是中上部). "NE"表示"东北"(也就是右上角), "CENTER"表示分配区域的正中间. 以此类推.
*运行程序*
现在, 运行程序. 你不必看代码. 只运行程序, 然后体会不同的pack参数对三个按钮的影响.
按钮A的容器是一个水平的洞 -- 它与按钮一样高.
按钮B的容器是一个竖直的洞 -- 它与按钮一样宽.
按钮C的容器是一个很大的洞 -- 它比按钮的宽和高都大.
如果在某个配置下, 按钮的位置与你想的不一样, 那么尝试去解释一下为啥会这样.
最后...
*一个有用的调试技巧*
注意pack是一个很麻烦的工作, 因为控件的位置会依赖于之前已有的控件. 也就是说, 如果有控件被pack到左侧了, 那么接下来的控件将会被pack到右侧. 而如果有控件pack到顶部了, 那么接下来的控件会被pack到底部. 这个很容易晕.
这里提供一个很有用的小技巧. 当你在布局时遇到了问题 -- 控件不按你想的布局 -- 那就给你的容器们一个不同的背景色, 比如:
bg='red' or bg='cyan' or bg='tan'
... 或黄色, 蓝色等等.
这会让你很快看到容器的排列方式. 一般这会就解决你的问题了.
- from Tkinter import *
-
-
class MyApp:
-
def __init__(self, parent):
-
-
#------ constants for controlling layout of buttons ------
-
button_width = 6
-
button_padx = "2m"
-
button_pady = "1m"
-
buttons_frame_padx = "3m"
-
buttons_frame_pady = "2m"
-
buttons_frame_ipadx = "3m"
-
buttons_frame_ipady = "1m"
-
# -------------- end constants ----------------
-
-
-
# set up Tkinter variables, to be controlled by the radio buttons
-
self.button_name = StringVar()
-
self.button_name.set("C")
-
-
self.side_option = StringVar()
-
self.side_option.set(LEFT)
-
-
self.fill_option = StringVar()
-
self.fill_option.set(NONE)
-
-
self.expand_option = StringVar()
-
self.expand_option.set(YES)
-
-
self.anchor_option = StringVar()
-
self.anchor_option.set(CENTER)
-
-
-
# -------------- end constants ----------------
-
-
self.myParent = parent
-
self.myParent.geometry("640x400")
-
-
### Our topmost frame is called myContainer1
-
self.myContainer1 = Frame(parent) ###
-
self.myContainer1.pack(expand=YES, fill=BOTH)
-
-
-
### We will use HORIZONTAL (left/right) orientation inside myContainer1.
-
### Inside myContainer1, we create control_frame and demo_frame.
-
-
# control frame - basically everything except the demo frame
-
self.control_frame = Frame(self.myContainer1) ###
-
self.control_frame.pack(side=LEFT, expand=NO, padx=10, pady=5, ipadx=5, ipady=5)
-
-
# inside control_frame we create a header label
-
# and a buttons_frame at the top,
-
# and demo_frame at the bottom
-
-
myMessage="This window shows the effects of the \nexpand, fill, and anchor packing options.\n"
-
Label(self.control_frame, text=myMessage, justify=LEFT).pack(side=TOP, anchor=W)
-
-
# buttons frame
-
self.buttons_frame = Frame(self.control_frame) ###
-
self.buttons_frame.pack(side=TOP, expand=NO, fill=Y, ipadx=5, ipady=5)
-
-
# demo frame
-
self.demo_frame = Frame(self.myContainer1) ###
-
self.demo_frame.pack(side=RIGHT, expand=YES, fill=BOTH)
-
-
-
### Inside the demo frame, we create top_frame and bottom_frame.
-
### These will be our demonstration frames.
-
# top frame
-
self.top_frame = Frame(self.demo_frame)
-
self.top_frame.pack(side=TOP, expand=YES, fill=BOTH) ###
-
-
# bottom frame
-
self.bottom_frame = Frame(self.demo_frame,
-
borderwidth=5, relief=RIDGE,
-
height=50,
-
bg="cyan",
-
) ###
-
self.bottom_frame.pack(side=TOP, fill=X)
-
-
-
### Now we will put two more frames, left_frame and right_frame,
-
### inside top_frame. We will use HORIZONTAL (left/right)
-
### orientation within top_frame.
-
-
# left_frame
-
self.left_frame = Frame(self.top_frame, background="red",
-
borderwidth=5, relief=RIDGE,
-
width=50,
-
) ###
-
self.left_frame.pack(side=LEFT, expand=NO, fill=Y)
-
-
-
### right_frame
-
self.right_frame = Frame(self.top_frame, background="tan",
-
borderwidth=5, relief=RIDGE,
-
width=250
-
)
-
self.right_frame.pack(side=RIGHT, expand=YES, fill=BOTH)
-
-
-
# now put a button in each of the interesting frames
-
button_names = ["A", "B", "C"]
-
side_options = [LEFT, TOP, RIGHT, BOTTOM]
-
fill_options = [X, Y, BOTH, NONE]
-
expand_options = [YES, NO]
-
anchor_options = [NW, N, NE, E, SE, S, SW, W, CENTER]
-
-
-
self.buttonA = Button(self.bottom_frame, text="A")
-
self.buttonA.pack()
-
self.buttonB = Button(self.left_frame, text="B")
-
self.buttonB.pack()
-
self.buttonC = Button(self.right_frame, text="C")
-
self.buttonC.pack()
-
self.button_with_name = {"A":self.buttonA, "B":self.buttonB, "C":self.buttonC}
-
-
# now we some subframes to the buttons_frame
-
self.button_names_frame = Frame(self.buttons_frame, borderwidth=5)
-
self.side_options_frame = Frame(self.buttons_frame, borderwidth=5)
-
self.fill_options_frame = Frame(self.buttons_frame, borderwidth=5)
-
self.expand_options_frame = Frame(self.buttons_frame, borderwidth=5)
-
self.anchor_options_frame = Frame(self.buttons_frame, borderwidth=5)
-
-
self.button_names_frame.pack( side=LEFT, expand=YES, fill=Y, anchor=N)
-
self.side_options_frame.pack( side=LEFT, expand=YES, anchor=N)
-
self.fill_options_frame.pack( side=LEFT, expand=YES, anchor=N)
-
self.expand_options_frame.pack(side=LEFT, expand=YES, anchor=N)
-
self.anchor_options_frame.pack(side=LEFT, expand=YES, anchor=N)
-
-
Label(self.button_names_frame, text="\nButton").pack()
-
Label(self.side_options_frame, text="Side\nOption").pack()
-
Label(self.fill_options_frame, text="Fill\nOption").pack()
-
Label(self.expand_options_frame, text="Expand\nOption").pack()
-
Label(self.anchor_options_frame, text="Anchor\nOption").pack()
-
-
for option in button_names:
-
button = Radiobutton(self.button_names_frame, text=str(option), indicatoron=1,
-
value=option, command=self.button_refresh, variable=self.button_name)
-
button["width"] = button_width
-
button.pack(side=TOP)
-
-
for option in side_options:
-
button = Radiobutton(self.side_options_frame, text=str(option), indicatoron=0,
-
value=option, command=self.demo_update, variable=self.side_option)
-
button["width"] = button_width
-
button.pack(side=TOP)
-
-
for option in fill_options:
-
button = Radiobutton(self.fill_options_frame, text=str(option), indicatoron=0,
-
value=option, command=self.demo_update, variable=self.fill_option)
-
button["width"] = button_width
-
button.pack(side=TOP)
-
-
for option in expand_options:
-
button = Radiobutton(self.expand_options_frame, text=str(option), indicatoron=0,
-
value=option, command=self.demo_update, variable=self.expand_option)
-
button["width"] = button_width
-
button.pack(side=TOP)
-
-
for option in anchor_options:
-
button = Radiobutton(self.anchor_options_frame, text=str(option), indicatoron=0,
-
value=option, command=self.demo_update, variable=self.anchor_option)
-
button["width"] = button_width
-
button.pack(side=TOP)
-
-
self.cancelButtonFrame = Frame(self.button_names_frame)
-
self.cancelButtonFrame.pack(side=BOTTOM, expand=YES, anchor=SW)
-
-
self.cancelButton = Button(self.cancelButtonFrame,
-
text="Cancel", background="red",
-
width=button_width,
-
padx=button_padx,
-
pady=button_pady
-
)
-
self.cancelButton.pack(side=BOTTOM, anchor=S)
-
-
-
-
self.cancelButton.bind("", self.cancelButtonClick)
-
self.cancelButton.bind("", self.cancelButtonClick)
-
-
# set up the buttons in their initial position
-
self.demo_update()
-
-
-
def button_refresh(self):
-
button = self.button_with_name[self.button_name.get()]
-
properties = button.pack_info()
-
self.fill_option.set ( properties["fill"] )
-
self.side_option.set ( properties["side"] )
-
self.expand_option.set( properties["expand"] )
-
self.anchor_option.set( properties["anchor"] )
-
-
-
def demo_update(self):
-
button = self.button_with_name[self.button_name.get()]
-
button.pack(fill=self.fill_option.get()
-
, side=self.side_option.get()
-
, expand=self.expand_option.get()
-
, anchor=self.anchor_option.get()
-
)
-
-
-
def cancelButtonClick(self, event):
-
self.myParent.destroy()
-
-
-
root = Tk()
-
myapp = MyApp(root)
-
root.mainloop()
阅读(1014) | 评论(0) | 转发(0) |