본문 바로가기
Programming/TclTk

TK Pack 형상 관리자

by Hunveloper 2022. 9. 13.
728x90

Pack 형상 관리자

  • 형상 관리자는 화면에 widget을 배치
  • 각 widget마다 다른 종류의 형상 관리자를 사용
  • 형상 관리자는 부모 widget을 하나 사용하며 그 안에 여러 개의 자식 widget을 배치
  • 부모 widget은 보통 프레임
  • 하나의 widget은 한번에 하나의 형상 관리자에 의해서만 관리
  • widget이 형상 관리자와 연결되지 않으면 화면에 나타나지 않음
  • packer는 강력한 형상 관리자
  • 각 윈도우의 정확한 위치 대신, 어떤 방식으로 배치하는지 알려주면 packer가 알아서 배치
  • 본 글에서는 예제를 통해 packer 형상 관리자를 이용

모서리쪽에 붙이기

  • 두개의 프레임을 생성한 후 각각을 메인 윈도우의 위쪽에 붙임
  • 더 위쪽에 배치될 윈도우가 .one이며 그 아래에 .two 윈도우가 배치
  • 모서리 위치는 top, right, bottom, left 중 하나
# Make the main window black
. config -bg black

# Create and pack two frames
frame .one -width 40 -height 40 -bg white
frame .two -width 100 -height 50 -bg grey50
pack .one .two -side top
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 메인 윈도우는 두 개의 자식 윈도우를 담을 크기만큼만 지정
  • 기능을 해제하기 위해서 pack propagate명령을 사용
  • pack propagate 명령을 부모 프레임에 사용하면 자식 윈도우의 크기에 맞추어 변경되지 않음
# Make the main window black
. config -bg black

# Create and pack two frames
frame .one -width 40 -height 40 -bg white
frame .two -width 100 -height 50 -bg grey50
pack propagate . false
pack .one .two -side top
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

가로 세로 쌓기

  • 일반적으로 프레임 안에서 가로나 세로로 widget을 쌓을 수 있음
  • 만약 한 프레임 안의 자식 widget들에 대해 left와 top을 동시에 사용하면 오작동 발생 가능성
  • 이러한 경우는 자식 프레임을 만들어 다른 형태로 widget을 쌓는다
  • 앞의 예제에서 위쪽 프레임을 버튼에 가로로 배열
# Make the main window black
. config -bg black

# Create two frames
frame .one -bg white
frame .two -width 100 -height 50 -bg grey50
# Create a row of buttons
foreach b {alpha beta gamma} {
    button .one.$b -text $b
    pack .one.$b -side left
}
pack .one .two -side top
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 좀더 복잡한 배치를 위해 프레임을 중복하여 사용
# Make the main window black
. config -bg black
# Create two frames
frame .one -bg white
frame .two -width 100 -height 50 -bg grey50
# Create a row of buttons
foreach b {alpha beta} {
    button .one.$b -text $b
    pack .one.$b -side left
}
# Create a frame for two more buttons
frame .one.right
foreach b {delta epsilon} {
    button .one.right.$b -text $b
    pack .one.right.$b -side bottom
}
pack .one.right -side right
pack .one .two -side top
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

Cavity 모델

  • packing 알고리즘은 프레임 안의 남는 공간에 대해 cavity 모델을 사용
  • 메인 윈도우가 생성될 때 메인 프레임은 비어 있으며 widget을 배치할 자리가 있음
  • widget은 남은 공간의 한 면을 전부 차지
# Make the main window black
. config -bg black
# Pack two frames on the bottom
frame .one -width 100 -height 50 -bg grey50
frame .two -width 40 -height 40 -bg white
pack .one .two -side bottom
# Pack another frame to the right
frame .three -width 20 -height 20 -bg grey75
pack .three -side right
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 위의 예제에서 .three widget은 오른쪽에 배치되었지만 .two아래로는 내려가지 않음
  • .two widget이 bottom 면에 배치되어 있으므로 가로방향으로 한 면을 전부 차지했기 때문

팩킹 공간과 디스플레이 공간

  • packer는 팩킹 공간과 디스플레이 공간을 구분
  • 디스플레이 공간은 widget을 화면에 보여주기 위해 요청되는 구역
  • 팩킹 공간은 widget의 배치를 위해 허용하는 구역
  • 화면 구성상의 특징 때문에 팩킹 공간은 디스플레이 공간보다 더 클 수 있음
  • -fill 옵션은 디스플레이 공간이 차지하는 공간을 채우도록 만듬
#Make the main window black
. config -bg black

# pack two frames on the bottom
frame .one -width 100 -height 50 -bg grey50
frame .two -width 40 -height 40 -bg white

# Pack with fill enabled
pack .one .two -side bottom -fill x
frame .three -width 20 -height 20 -bg red
pack .three -side right -fill x
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • -fill x 옵션이 사용되면 위와 같이 자신이 차지하는 구역 전부에 꽉 채워져 화면에 나타남
  • fill 옵션은 다음과 같이 메뉴바를 만드는데 많이 사용
frame .menubar -bg white
frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar
foreach b {alpha beta} {
    button .menubar.$b -text $b
}
pack .menubar.alpha -side left
pack .menubar.beta -side right

# Let the menu bar fill along the top
pack .menubar -side top -fill x
pack .body
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 좀 더 많은 공간을 확보할 때는 padding을 지정한다. -ipadx 혹은 -ipady
frame .menubar -bg white
frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar
foreach b {alpha beta} {
    button .menubar.$b -text $b
}
pack .menubar.alpha -side left -ipady 10
pack .menubar.beta -side right -ipadx 10

# Let the menu bar fill along the top
pack .menubar -side top -fill x -ipady 5
pack .body
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 내부 패딩의 크기를 다르게 했기에 alpha와 beta 버튼의 크기는 다름
  • 버튼은 -padx와 -pady의 또다른 패딩 옵션을 제공
  • -padx와 -pady 옵션은 버튼 안에 들어가는 글자가 버튼의 경계보다 안쪽에 들어가게 함
# Foo has internal padding from the packer
button .foo -text Foo -anchor e -padx 0 -pady 0
pack .foo -side right -ipadx 15 -ipady 10

#Bar has its own padding
button .bar -text Bar -anchor e -pady 15 -padx 10
pack .bar -side right -ipadx 0 -ipady 0
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 원래 -padx와 -pady 옵션은 외부 패딩을 정하기 위해 사용
  • 이것은 widget의 바깥 부분에 들어가는 패딩이며 3차원 효과를 나타내는 부분
. config -borderwidth 10
# OK is the default button
frame .ok -borderwidth 2 -relief sunken
button .ok.b -text OK
pack .ok.b -padx 5 -pady 5
# Cancel is not
button .cancel -text Cancel
pack .ok .cancel -side left -padx 5 -pady 5
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

크기 확장과 크기 조절

  • -expand true 옵션은 widget이 자기 자리가 아니지만 비어 있는 곳까지 확장하도록 함
  • -expand 옵션이 사용되는 더 일반적인 예는 크기를 변경할 수 있는 윈도우
  • 윈도우가 더 커지면 새로 만들어진 남는 공간을 사용하라고 widget들에게 말해야 함
  • 윈도우의 크기는 사용자가 직접 변경할 수 있고 wm geometry 명령을 이용해 변경도 가능
  • 기본적으로 윈도우의 크기는 변경불가능
  • wm minsize나 wm maxsize 명령은 윈도우의 크기를 바꿀 수 있게 하는 부가적인 효과를 가짐
# Make the main window black
. config -bg black

# Create and pack two frames
frame .menubar -bg white
frame .body -width 150 -height 50 -bg grey50

# Create buttons at either end of the menubar
foreach b {alpha beta} {
    button .menubar.$b -text $b
}
pack .menubar.alpha -side left
pack .menubar.beta -side right

#Let the menu bar fill along the top
pack .menubar -side top -fill x
pack .body

# Resize the main window to be bigger
wm geometry . 200x100
# Allow interactive resizing
wm minsize . 100 50
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

실행 시 뜨는 창의 크기

최소로 만들었을 때 유지되는 창의 크기

  • 다음 명령을 실행하면 윈도우는 아래와 같이 바뀜
pack .body -expand true -fill both

  • 그러나 하나의 부모 widget 밑에 있는 두 개 이상의 widget이 모두 -expand 옵션을 사용할 경우 각 widget이 비례적으로 남은 공간을 나누어 가짐
  • 위의 pack 명령 대신 아래 명령을 실행하면 화면이 바뀜
pack .menubar -expand true -fill x
pack .body -expand true -fill both

Anchoring

  • widget이 디스플레이 공간보다 더 많은 팩킹 공간이 있을 때에는 -anchor 옵션을 사용해 패킹 공간에서 위치 지정 가능
  • 기본 위치는 center, 가능한 위치는 n, ne, e, se, s, sw, w, nw임
# Make the main window black
. config -bg black

# Create two frames to hold open the cavity
frame .prop -bg white -height 80 -width 20
frame .base -width 120 -height 20 -bg grey50
pack .base -side bottom

# Float a label and the prop in the cavity
label .foo -text Foo
pack .prop .foo -side right -expand true
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • .base 프레임은 바닥에 배치
  • .prop와 .foo 레이블은 오른쪽에 배치되지만 fill 옵션은 선택되지 않음
  • 그에 따라 .foo는 기본적으로 중앙에 배치됨
  • 다음 예는 -anchor 옵션을 사용하는 예
# Make the main window black
. config -bg black

# Create two frames to hold open the cavity
frame .prop -bg white -height 80 -width 20
frame .base -width 120 -height 20 -bg grey50
pack .base -side bottom

# Float a label and the prop
# Change their position with anchors
label .foo -text Foo
pack .prop .foo -side right -expand true -anchor sw
pack .foo -side right -expand true -anchor ne
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

패킹 순서

  • packer는 프레임에 들어가는 자식 widget들의 순서를 유지
  • 기본적으로 새로 추가된 widget은 가장 마지막 팩킹 순서 뒤에 추가됨
  • 팩킹 순서는 가장 높은 팩킹 순서를 가지는 widget이 모서리쪽에 가깝게 배치
  • -before나 -after 팩킹 옵션을 사용하면 팩킹 순서를 바꿀 수 있음
  • 이미 들어간 widget의 팩킹 순서도 변경 가능
#Create five labels in order
foreach label {one two three four five} {
    label .$label -text $label
    pack .$label -side left -padx 5
}
#ShuffleUp moves a widget to the beginning of the order
proc ShuffleUp { parent child } {
    set first [lindex [pack slaves $parent] 0]
    pack $child -in $parent -before $first
}
#ShuffleDown moves a widget to the end of the order
proc ShuffleDown { parent child } {
    pack $child -in $parent
}
  • 위의 예제를 실행하면 아래의 화면이 만들어짐

  • 여기서 다음 명령어를 실행하면 아래와 같이 변경됨
ShuffleUp . .five
ShuffleDown . .three

  • pack slaves 명령은 팩킹 순서로 자식 widget의 리스트를 반환
  • 일반적으로 모든 widget은 그 부모의 자손 window에는 어디에나 포함 가능
  • 예를 들어 .a.b widget은 .a, .a.c, .a.d.e.f 등의 window에 모두 포함가능
  • -in 옵션은 다른 부모를 선택하게 해줌
  • pack forget 명령은 포함된 widget을 끄집어 냄
728x90
728x90

'Programming > TclTk' 카테고리의 다른 글

Tcl namespace eval command  (1) 2022.09.16
TK X 이벤트와 Tcl 명령의 연결  (0) 2022.09.13
TK 예제로 배우는 Tk  (0) 2022.09.08
TK 기초  (0) 2022.09.07
TCL 스크립트 라이브러리  (0) 2022.09.06

댓글