본문으로 바로가기

SMARTPACK

category Tcl & Tk/확장 패키지 (Extension Package) 2025. 8. 27. 11:45

홈페이지 : http://graphics.stanford.edu/~jedavis/p … index.html

Tools to make packing Tcl widgets a little easier.

by James Davis (c)2000

 

Tcl로 UI 인터페이스를 설계할 때 가장 큰 문제 중 하나는 packer(패커)를 사용하는 것입니다. 위젯을 프로그램적으로 정의하는 것은 꽤 편리합니다. 하지만 이들을 배치하려면 프레임을 사용해서 레이아웃을 구성해야 합니다. 만약 미리 정확한 배치 구조를 알고 있다면 이는 쉽습니다. 하지만 변경이 필요할 때는 추가적인 계층 구조가 요구되는 경우가 많고, 위젯이 프레임을 기준으로 이름이 지정되는 방식 때문에 모든 위젯의 이름을 다시 지정해야 할 때가 많습니다. 이것은 정말 번거로운 일입니다. Smartpack은 이러한 과정을 조금 덜 고통스럽게 만들고, 코드도 좀 더 읽기 쉽게 해주는 몇 가지 루틴을 제공합니다.

 

One of the chief problems with designing interfaces for TCL is using the packer. Its fairly convenient to define widgets programmatically. However to arrange them, we need to use frames to lay things out. If you know the exact arrangement beforehand then this is easy. However, when we want to make changes, an extra layer of heirarchy is often required, and because of the way widgets are named relative to their frame, we need to go back and rename all the widgets. This is a real hassle. Smartpack defines some routines that make this a little less painful, and code a little easier to read.

For example, suppose we want to group some widgets:

frame .frame
button .frame.b1 -text b1
button .frame.b2 -text b2
button .frame.b3 -text b3
pack .frame.b1 .frame.b2 .frame.b3
pack .frame

 

If we decide that we want to insert another layer, we have

frame .frame
button .frame.b1 -text b1
frame .frame.newlevel
button .frame.newlevel.b2 -text b2
button .frame.newlevel.b2 -text b3
pack .frame.newlevel.b2 .frame.newlevel.b3
pack .frame.b1 .frame.newlevel
pack .frame

 

Note that we added two new lines, and changed three of the original six lines. All this for a single conceptual change.

Part of the problem is that when we define widgets we have to explicitly give the widget path, rather than just saying 'Please give me a new widget in the current frame.' If we could define widgets relative to some current state, then when we changed the heirarchy, the widgets would just appear in new current level when they are defined, without actually changing the defining code.

A second problem, is that we have to explicitly pack all the widgets we built. Often we'd like to just 'pack all widgets'

So, we can define a couple new constructs which begin and end levels of the heirarchy, and then declare widgets relative to these.

startframe .frame
button $smartpack.b1 -text b1
button $smartpack.b2 -text b2
button $smartpack.b3 -text b3
packframe
pack .frame

 

Lets look at whats new here. We use 'startframe' rather than 'frame' to declare a new frame. This sets up a current context. Then we can use $smartpack to reference this notion of current context. When we finish with the frame we use 'packframe' to pack all the widgets currently defined in the frame. Note that we skip explicitly naming the widgets.

Lets look at what we have to do now to add a level of heirarchy.

startframe .frame
button $smartpack.b1 -text b1
startframe newlevel
button $smartpack.b2 -text b2
button $smartpack.b3 -text b3
packframe
packframe
pack .frame

In this case we only had to add two lines, but didn't have to change any of the existing lines of code. We added one line to create a new current context, and one line to pack things in this context. Also note that since this is a sub-frame we only specified a relative frame name 'newlevel', rather than a complete path '.frame.newlevel'.

In some cases we might want the code to more clearly indicate the frame heirarchy, so we can use one more new construct to combine the startframe and packframe commands, like this:

smartframe .frame {
button $smartpack.b1 -text b1
button $smartpack.b2 -text b2
button $smartpack.b3 -text b3
}
pack .frame

Note that we changed from 'startframe' to 'smartframe', and the packframe at the end became implicit. After changing we have:

smartframe .frame {
	button $smartpack.b1 -text b1
	smartframe newlevel {
		button $smartpack.b2 -text b2
		button $smartpack.b3 -text b3
	}
}
pack .frame

We've added one new command, and a level of {} braces in order to change the heirarchy. In addition if we use an editor that auto-indents then the logical widget heirarchy will be reflected in the code indentation naturally. This can improve the readability of the code quite a bit on complex arrangements.

Here is a more complete sytax example:

smartframe ".frame -relief groove" {
	button $smartpack.b1 -text b1
	smartframe "newlevel -bd 2" {
		smartframe moreLevels {
			button $smartpack.b2 -text b2
			button $smartpack.b3 -text b3
		}
	} -anchor w
} -side left
startframe .frame2
button $smartpack.b1 -text "A different b1"
packframe
pack .frame .frame2

Finally, here is a reference:

proc startframe {fname args}
# We define a new frame. If fname starts with a dot (.), then
# it is an absolute path, otherwise fname defines a relative name
# for the new frame under the previous current context. Often a top
# level frame will be absolute, and all the subframes will be relative.
# The parameter args, are options that pass through to the 'frame'
# command. In addition we set the global variable $smartpack to
# be the name of the current context. This variable is declared
# in the correct scope so that it can just be used. Also the local
# variable $sp is set as a convenient alias to $smartpack.

proc packframe {args}
# End the current frame context. Pack all child widgets of the
# current context, using 'args' as options to the 'pack' command.
# In addition, pop one level from the global variable $smartpack.
# Note that $smartpack is not set to what it was _before_ the startframe
# command, it just pops one level up, so that .frame.newlevel.moreLevels
# becomes .frame.newlevel after the packframe command.

proc smartframe {fname body args}
# Define a frame context. fname is the name of the frame using the
# same absolute and relative rules as for startframe. 'body' defines
# the set of commands that should run in this current frame context.
# And 'args' pass through to the final 'pack' commands. Note that
# options intended for the initial 'frame' command can be included
# in the fname parameter by using quotation marks. As in
# smartframe ".frame -bd 2" {}

smartpack.tcl
0.01MB

'Tcl & Tk > 확장 패키지 (Extension Package)' 카테고리의 다른 글

yajl-tcl 1.8.1  (0) 2025.08.27
TclMixer 1.2.3  (0) 2025.08.27
Extral 2.1.0  (0) 2025.08.27
tcljudy 1.0.1  (0) 2025.08.27
dictionary 1.0.1  (0) 2025.08.27