ZetCode

Tcl/Tk 中的布局管理

最后修改于 2023 年 10 月 18 日

在本 Tcl/Tk 编程教程中,我们将介绍布局管理器。

当我们设计应用程序的 GUI 时,我们决定使用哪些小部件以及如何在应用程序中组织这些小部件。为了组织我们的小部件,我们使用称为布局管理器的专用非可见对象。

有两种小部件:容器及其子项。容器将其子项分组到合适的布局中。

Tk 有三个内置的布局管理器:packgridplace 管理器。pack 几何管理器以垂直和水平框的形式组织小部件。grid 几何管理器将小部件放置在二维网格中。最后,place 几何管理器使用绝对定位将小部件放置在其容器上。

绝对定位

在大多数情况下,程序员应该使用布局管理器。在少数情况下,我们可以使用绝对定位。在绝对定位中,程序员以像素为单位指定每个小部件的位置和大小。如果调整窗口大小,小部件的大小和位置不会改变。应用程序在各种平台上看起来有所不同,在 Linux 上看起来可以的,在 Mac OS 上可能看起来不好。更改应用程序中的字体可能会破坏布局。如果我们将应用程序翻译成另一种语言,我们必须重新进行布局。

absolute.tcl
#!/usr/bin/wish

# ZetCode Tcl/Tk tutorial
#
# In this script, we lay out images
# using absolute positioning.
#
# Author: Jan Bodnar
# Website: www.zetcode.com

package require Img


frame .fr -background "#333"
pack .fr -fill both -expand 1

image create photo img1 -file "bardejov.jpg"
label .fr.lbl1 -image img1
place .fr.lbl1 -x 20 -y 20

image create photo img2 -file "rotunda.jpg"
label .fr.lbl2 -image img2
place .fr.lbl2 -x 40 -y 160

image create photo img3 -file "mincol.jpg"
label .fr.lbl3 -image img3
place .fr.lbl3 -x 170 -y 50


wm title . "absolute" 
wm geometry . 300x280+300+300

在此示例中,我们使用绝对定位放置三个图像。我们使用 place 几何管理器。

package require Img

我们使用 Img 包来显示 JPG 图像。

$ sudo apt install libtk-img

在 Linux 上,我们必须安装 libtk-img 包。

package require Img

要显示 JPG 图像,我们使用 Img 包。

frame .fr -background "#333"

我们的 frame 将有一个深灰色的背景。

image create photo img1 -file "bardejov.jpg"

我们从当前工作目录中的图像创建一个 photo image 对象。

label .fr.lbl1 -image img1

我们创建一个带有图像的 label。标签可以包含文本或图像。

place .fr.lbl1 -x 20 -y 20

标签放置在 frame 上,坐标为 x=20, y=20。绝对定位使用 place 命令完成。

Absolute positioning
图:绝对定位

按钮示例

在下面的示例中,我们将两个按钮放置在窗口的右下角。我们使用 pack 管理器。

buttons.tcl
#!/usr/bin/wish

# ZetCode Tcl/Tk tutorial
#
# In this script, we use the pack
# manager to place two buttons in 
# bottom-right corner of the window
#
# Author: Jan Bodnar
# Website: www.zetcode.com

frame .fr
pack .fr -fill both -expand 1

frame .fr.pnl -relief raised -borderwidth 1
pack .fr.pnl -fill both -expand 1

ttk::button .fr.cb -text "Close"
pack .fr.cb -padx 5 -pady 5 -side right

ttk::button .fr.ok -text "OK"
pack .fr.ok -side right

wm title . "buttons" 
wm geometry . 350x300+300+300

我们有两个 frame。有一个基本 frame 和一个附加 frame,它将在两个方向上展开,并将两个按钮推到基本 frame 的底部。按钮放置在一个水平框中,并放置在该框的右侧。

frame .fr.pnl -relief raised -borderwidth 1
pack .fr.pnl -fill both -expand 1

我们创建另一个 frame 小部件。此小部件占据大部分区域。我们更改 frame 的边框,以便 frame 可见。默认情况下它是平的。pack 管理器在两个方向上展开 frame。水平和垂直。

ttk::button .fr.cb -text "Close"
pack .fr.cb -padx 5 -pady 5 -side right

创建关闭按钮。它被放入一个水平框中。-side 选项将创建一个水平框布局,其中按钮放置在框的右侧。-padx-pady 选项将在小部件之间留出一些空间。-padx 在按钮小部件之间以及在关闭按钮和根窗口的右边框之间留出一些空间。-pady 在按钮小部件之间以及在 frame 和根窗口的边框之间留出一些空间。

pack .fr.ok -side right

ok 按钮放置在关闭按钮旁边。它们之间有 5px 的空间。

Buttons example
图:按钮示例

计算器

我们使用 Tk grid 几何管理器创建一个计算器的骨架。

calculator.tcl
#!/usr/bin/wish

# ZetCode Tcl/Tk tutorial
#
# In this script, we use the grid manager
# to create a skeleton of a calculator.
#
# Author: Jan Bodnar
# Website: www.zetcode.com


frame .fr -padx 5 -pady 5
pack .fr -fill both -expand 1

ttk::style configure TButton -width 8 -height 8 -font "serif 10"

entry .fr.ent
grid .fr.ent -row 0 -columnspan 4 -sticky we

ttk::button .fr.cls -text "Cls"
grid .fr.cls -row 1 -column 0
ttk::button .fr.bck -text "Back"
grid .fr.bck -row 1 -column 1
ttk::button .fr.lbl
grid .fr.lbl -row 1 -column 2
ttk::button .fr.clo -text "Close"
grid .fr.clo -row 1 -column 3
ttk::button .fr.sev -text "7"
grid .fr.sev -row 2 -column 0
ttk::button .fr.eig -text "8"
grid .fr.eig -row 2 -column 1
ttk::button .fr.nin -text "9"
grid .fr.nin -row 2  -column 2
ttk::button .fr.div -text "/"
grid .fr.div -row 2 -column 3

ttk::button .fr.fou -text "4"
grid .fr.fou -row 3 -column 0
ttk::button .fr.fiv -text "5"
grid .fr.fiv -row 3 -column 1
ttk::button .fr.six -text "6"
grid .fr.six -row 3 -column 2
ttk::button .fr.mul -text "*"
grid .fr.mul -row 3 -column 3

ttk::button .fr.one -text "1"
grid .fr.one -row 4 -column 0
ttk::button .fr.two -text "2"
grid .fr.two -row 4 -column 1
ttk::button .fr.thr -text "3"
grid .fr.thr -row 4 -column 2
ttk::button .fr.mns -text "-"
grid .fr.mns -row 4 -column 3

ttk::button .fr.zer -text "0"
grid .fr.zer -row 5 -column 0
ttk::button .fr.dot -text "."
grid .fr.dot -row 5 -column 1
ttk::button .fr.equ -text "="
grid .fr.equ -row 5 -column 2
ttk::button .fr.pls -text "+"
grid .fr.pls -row 5 -column 3


grid columnconfigure .fr 0 -pad 3
grid columnconfigure .fr 1 -pad 3
grid columnconfigure .fr 2 -pad 3
grid columnconfigure .fr 3 -pad 3

grid rowconfigure .fr 0 -pad 3
grid rowconfigure .fr 1 -pad 3
grid rowconfigure .fr 2 -pad 3
grid rowconfigure .fr 3 -pad 3
grid rowconfigure .fr 4 -pad 3


wm title . "calculator"
wm geometry . +300+300

在此示例中,我们使用 grid 管理器在 frame 容器小部件中组织按钮。

ttk::style configure TButton -width 8 -height 8 -font "serif 10" 

我们配置主题 button 小部件以具有特定的字体并具有一些内部填充。

entry .fr.ent 
grid .fr.ent -row 0 -columnspan 4 -sticky we

entry 小部件是显示数字的地方。小部件放置在第一行,并将跨越所有四列。小部件可能不会占用网格中单元格分配的所有空间。-sticky 选项将在给定方向上展开小部件。在我们的例子中,我们确保 entry 小部件从左到右展开。

ttk::button .fr.cls -text "Cls" 

cls 按钮放置在第二行和第一列。请注意,行和列从零开始。ttk::button 是一个主题按钮。

grid columnconfigure .fr 0 -pad 3
...
grid rowconfigure .fr 0 -pad 3  

我们使用 columnconfigurerowconfigure 命令来定义网格列和行中的一些空间。这样我们就可以实现按钮之间有一些空间。

Calculator
图:计算器

Windows 示例

以下示例使用 grid 几何管理器创建 windows 对话框。对话框来自 JDeveloper 应用程序。

windows.tcl
#!/usr/bin/wish

# ZetCode Tcl/Tk tutorial
#
# In this script, we use the grid
# manager to create a more complicated
# layout.
#
# Author: Jan Bodnar
# Website: www.zetcode.com


frame .fr -padx 5 -pady 5
pack .fr -fill both -expand 1

label .fr.lbl -text Windows
grid .fr.lbl -sticky w -pady 4 -padx 5
        
text .fr.area
grid .fr.area -row 1 -column 0 -columnspan 2 \
    -rowspan 4 -padx 5 -sticky ewsn 

ttk::button .fr.act -text Activate
grid .fr.act -row 1 -column 3

ttk::button .fr.cls -text Close
grid .fr.cls -row 2 -column 3 -pady 4

ttk::button .fr.hlp -text Help
grid .fr.hlp -row 5 -column 0 -padx 5

ttk::button .fr.ok -text OK
grid .fr.ok -row 5 -column 3

grid columnconfigure .fr 1 -weight 1
grid columnconfigure .fr 3 -pad 7

grid rowconfigure .fr 3 -weight 1
grid rowconfigure .fr 5 -pad 7

wm title . "Windows" 
wm geometry . 350x300+300+300

在此示例中,我们使用 label 小部件、text 小部件和四个按钮。

label .fr.lbl -text Windows
grid .fr.lbl -sticky w -pady 4 -padx 5

创建 label 小部件并将其放入网格中。如果未指定列和行,则假定第一列或第一行。标签粘在西边,并且在其文本周围有一些填充。

text .fr.area
grid .fr.area -row 1 -column 0 -columnspan 2 \
    -rowspan 4 -padx 5 -sticky ewsn 

创建 text 小部件并从第二行第一列开始。它跨越 2 列和 4 行。小部件和根窗口的左边框之间有 4px 的空间。最后,它粘在所有四个边上。因此,当调整窗口大小时,text 小部件在所有方向上增长。

grid columnconfigure .fr 1 -weight 1
grid columnconfigure .fr 3 -pad 7

grid rowconfigure .fr 3 -weight 1
grid rowconfigure .fr 5 -pad 7

我们在网格中的小部件之间定义了一些空间。最大的空间位于 text 小部件和按钮之间。

Windows example
图:Windows 示例

在本 Tcl/Tk 教程中,我们提到了小部件的布局管理。