Chinaunix首页 | 论坛 | 博客
  • 博客访问: 73443
  • 博文数量: 26
  • 博客积分: 628
  • 博客等级: 中士
  • 技术积分: 315
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-22 11:57
文章分类

全部博文(26)

文章存档

2012年(4)

2011年(19)

2010年(3)

我的朋友

分类: Python/Ruby

2011-04-29 15:38:27


在本程序中, 我们来讨论几个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'

... 或黄色, 蓝色等等.

这会让你很快看到容器的排列方式. 一般这会就解决你的问题了.

  1. from Tkinter import *

  2. class MyApp:
  3.     def __init__(self, parent):
  4.         
  5.         #------ constants for controlling layout of buttons ------
  6.         button_width = 6         
  7.         button_padx = "2m"
  8.         button_pady = "1m"
  9.         buttons_frame_padx = "3m"
  10.         buttons_frame_pady = "2m"         
  11.         buttons_frame_ipadx = "3m"
  12.         buttons_frame_ipady = "1m"
  13.         # -------------- end constants ----------------


  14.         # set up Tkinter variables, to be controlled by the radio buttons
  15.         self.button_name = StringVar()
  16.         self.button_name.set("C")
  17.         
  18.         self.side_option = StringVar()
  19.         self.side_option.set(LEFT)
  20.         
  21.         self.fill_option = StringVar()
  22.         self.fill_option.set(NONE)

  23.         self.expand_option = StringVar()
  24.         self.expand_option.set(YES)
  25.         
  26.         self.anchor_option = StringVar()        
  27.         self.anchor_option.set(CENTER)
  28.         
  29.         
  30.         # -------------- end constants ----------------
  31.         
  32.         self.myParent = parent
  33.         self.myParent.geometry("640x400")

  34.         ### Our topmost frame is called myContainer1
  35.         self.myContainer1 = Frame(parent) ###
  36.         self.myContainer1.pack(expand=YES, fill=BOTH)


  37.         ### We will use HORIZONTAL (left/right) orientation inside myContainer1.
  38.         ### Inside myContainer1, we create control_frame and demo_frame.
  39.         
  40.         # control frame - basically everything except the demo frame
  41.         self.control_frame = Frame(self.myContainer1) ###
  42.         self.control_frame.pack(side=LEFT, expand=NO, padx=10, pady=5, ipadx=5, ipady=5)     
  43.         
  44.         # inside control_frame we create a header label
  45.         # and a buttons_frame at the top,
  46.         # and demo_frame at the bottom
  47.         
  48.         myMessage="This window shows the effects of the \nexpand, fill, and anchor packing options.\n"
  49.         Label(self.control_frame, text=myMessage, justify=LEFT).pack(side=TOP, anchor=W)
  50.         
  51.         # buttons frame
  52.         self.buttons_frame = Frame(self.control_frame) ###
  53.         self.buttons_frame.pack(side=TOP, expand=NO, fill=Y, ipadx=5, ipady=5)

  54.         # demo frame
  55.         self.demo_frame = Frame(self.myContainer1) ###
  56.         self.demo_frame.pack(side=RIGHT, expand=YES, fill=BOTH)             


  57.         ### Inside the demo frame, we create top_frame and bottom_frame.
  58.         ### These will be our demonstration frames.                         
  59.         # top frame
  60.         self.top_frame = Frame(self.demo_frame)
  61.         self.top_frame.pack(side=TOP, expand=YES, fill=BOTH) ###

  62.         # bottom frame
  63.         self.bottom_frame = Frame(self.demo_frame,
  64.             borderwidth=5,     relief=RIDGE,
  65.             height=50,
  66.             bg="cyan",
  67.             ) ###    
  68.         self.bottom_frame.pack(side=TOP, fill=X)


  69.         ### Now we will put two more frames, left_frame and right_frame,
  70.         ### inside top_frame. We will use HORIZONTAL (left/right)
  71.         ### orientation within top_frame.
  72.         
  73.         # left_frame        
  74.         self.left_frame = Frame(self.top_frame,    background="red",
  75.             borderwidth=5,     relief=RIDGE,
  76.             width=50,
  77.             ) ###        
  78.         self.left_frame.pack(side=LEFT, expand=NO, fill=Y)


  79.         ### right_frame
  80.         self.right_frame = Frame(self.top_frame, background="tan",
  81.             borderwidth=5,     relief=RIDGE,
  82.             width=250
  83.             )
  84.         self.right_frame.pack(side=RIGHT, expand=YES, fill=BOTH)     


  85.         # now put a button in each of the interesting frames
  86.         button_names = ["A", "B", "C"]    
  87.         side_options = [LEFT, TOP, RIGHT, BOTTOM]    
  88.         fill_options = [X, Y, BOTH, NONE]
  89.         expand_options = [YES, NO]
  90.         anchor_options = [NW, N, NE, E, SE, S, SW, W, CENTER]
  91.         
  92.     
  93.         self.buttonA = Button(self.bottom_frame, text="A")
  94.         self.buttonA.pack()
  95.         self.buttonB = Button(self.left_frame, text="B")
  96.         self.buttonB.pack()
  97.         self.buttonC = Button(self.right_frame, text="C")
  98.         self.buttonC.pack()    
  99.         self.button_with_name = {"A":self.buttonA, "B":self.buttonB, "C":self.buttonC}    

  100.         # now we some subframes to the buttons_frame
  101.         self.button_names_frame = Frame(self.buttons_frame, borderwidth=5)
  102.         self.side_options_frame = Frame(self.buttons_frame, borderwidth=5)
  103.         self.fill_options_frame = Frame(self.buttons_frame, borderwidth=5)
  104.         self.expand_options_frame = Frame(self.buttons_frame, borderwidth=5)
  105.         self.anchor_options_frame = Frame(self.buttons_frame, borderwidth=5)

  106.         self.button_names_frame.pack( side=LEFT, expand=YES, fill=Y, anchor=N)
  107.         self.side_options_frame.pack( side=LEFT, expand=YES, anchor=N)        
  108.         self.fill_options_frame.pack( side=LEFT, expand=YES, anchor=N)
  109.         self.expand_options_frame.pack(side=LEFT, expand=YES, anchor=N)
  110.         self.anchor_options_frame.pack(side=LEFT, expand=YES, anchor=N)
  111.                     
  112.         Label(self.button_names_frame, text="\nButton").pack()
  113.         Label(self.side_options_frame, text="Side\nOption").pack()
  114.         Label(self.fill_options_frame, text="Fill\nOption").pack()
  115.         Label(self.expand_options_frame, text="Expand\nOption").pack()
  116.         Label(self.anchor_options_frame, text="Anchor\nOption").pack()        
  117.         
  118.         for option in button_names:
  119.             button = Radiobutton(self.button_names_frame, text=str(option), indicatoron=1,
  120.                 value=option, command=self.button_refresh, variable=self.button_name)
  121.             button["width"] = button_width
  122.             button.pack(side=TOP)

  123.         for option in side_options:
  124.             button = Radiobutton(self.side_options_frame, text=str(option), indicatoron=0,
  125.                 value=option, command=self.demo_update, variable=self.side_option)
  126.             button["width"] = button_width
  127.             button.pack(side=TOP)
  128.                                 
  129.         for option in fill_options:
  130.             button = Radiobutton(self.fill_options_frame, text=str(option), indicatoron=0,
  131.                 value=option, command=self.demo_update, variable=self.fill_option)
  132.             button["width"] = button_width
  133.             button.pack(side=TOP)

  134.         for option in expand_options:
  135.             button = Radiobutton(self.expand_options_frame, text=str(option), indicatoron=0,
  136.                 value=option, command=self.demo_update, variable=self.expand_option)
  137.             button["width"] = button_width
  138.             button.pack(side=TOP)
  139.     
  140.         for option in anchor_options:
  141.             button = Radiobutton(self.anchor_options_frame, text=str(option), indicatoron=0,
  142.                 value=option, command=self.demo_update, variable=self.anchor_option)
  143.             button["width"] = button_width
  144.             button.pack(side=TOP)

  145.         self.cancelButtonFrame = Frame(self.button_names_frame)
  146.         self.cancelButtonFrame.pack(side=BOTTOM, expand=YES, anchor=SW)
  147.         
  148.         self.cancelButton = Button(self.cancelButtonFrame,
  149.             text="Cancel", background="red",
  150.             width=button_width,
  151.             padx=button_padx,
  152.             pady=button_pady
  153.             )                
  154.         self.cancelButton.pack(side=BOTTOM, anchor=S)
  155.         

  156.         
  157.         self.cancelButton.bind("", self.cancelButtonClick)
  158.         self.cancelButton.bind("", self.cancelButtonClick)
  159.         
  160.         # set up the buttons in their initial position
  161.         self.demo_update()


  162.     def button_refresh(self):
  163.         button = self.button_with_name[self.button_name.get()]
  164.         properties = button.pack_info()
  165.         self.fill_option.set ( properties["fill"] )
  166.         self.side_option.set ( properties["side"] )
  167.         self.expand_option.set( properties["expand"] )
  168.         self.anchor_option.set( properties["anchor"] )


  169.     def demo_update(self):
  170.         button = self.button_with_name[self.button_name.get()]
  171.         button.pack(fill=self.fill_option.get()
  172.             , side=self.side_option.get()
  173.             , expand=self.expand_option.get()
  174.             , anchor=self.anchor_option.get()
  175.             )
  176.         
  177.         
  178.     def cancelButtonClick(self, event):
  179.         self.myParent.destroy()


  180. root = Tk()
  181. myapp = MyApp(root)
  182. root.mainloop()
阅读(1014) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~