bonkora 님이 제공해 주신 강좌입니다.
grid 명령 사용의 실제 1
윈도에 위젯을 배치할 때 사용할 수 있는 명령이 몇 가지 있습니다. 저는 그중 grid 명령을 주로 사용합니다. 이 글에서 grid 명령을 처음 접하시는 분들을 위하여 제가 주로 사용하는 방법으로 설명드리고자 합니다. 보시는 분들에게 유용했으면 좋겠습니다.
시험 삼아 만들어볼 프로젝트는 계산기인데, 엔트리 위젯에 수식을 입력하면 결과를 또 다른 위젯에 보여주는 방식입니다. 일단 엔트리 위젯 두 개가 필요할 것이고 계산하기 버튼과 지우기 버튼을 달 것입니다. 일단 아래와 같이 코딩을 하였습니다.
label .l1 -text "수식:"
entry .e1 -textvariable expression
label .l2 -text "결과:"
entry .e2 -textvariable result
button .b1 -text "계산하기" -command {
if [catch {expr $expression}] {
tk_messageBox -message "정확히 입력해 주십시오."
} else {
set result [expr $expression]
}
}
button .b2 -text "지우기" -command {set expression ""; set result ""}
grid .l1 .e1
grid .l2 .e2
grid .b1 .b2
이렇게 하면 이런 결과가 나옵니다.
수식을 입력하고 계산하기 버튼을 누르면 에러가 있으면 에러메시지를, 그렇지 않으면 답을 보여줍니다. 에러처리까지 된, 가장 간단한 형태의 계산기가 되었습니다. 그런데 라벨 위젯과 계산하기 버튼, 엔트리 위젯과 지우기 버튼이 각각 같은 칼럼에 놓여 보기가 별로 좋지 않습니다. 엔트리가 있는 부분과 버튼이 있는 부분을 독립적으로 배치하는 게 좋겠습니다. 그렇게 하려면 프레임을 두 개 만들어서 각 프레임에 엔트리와 버튼을 넣어야겠습니다.
frame .f1
label .f1.l1 -text "수식:"
entry .f1.e1 -textvariable expression
label .f1.l2 -text "결과:"
entry .f1.e2 -textvariable result
frame .f2
button .f2.b1 -text "계산하기" -command {
if [catch {expr $expression}] {
tk_messageBox -message "정확히 입력해 주십시오."
} else {
set result [expr $expression]
}
}
button .f2.b2 -text "지우기" -command {set expression ""; set result ""}
# 프레임을 놓는다
grid .f1
# 배치된 프레임에 위젯을 배치한다
grid .f1.l1 .f1.e1
grid .f1.l2 .f1.e2
grid .f2
grid .f2.b1 .f2.b2
이렇게 하면 이렇게 보입니다.
조금 나아 보이는데 창의 가장자리와 위젯의 거리랑 버튼 사이의 간격을 좀 더 띄우고 폰트 크기를 조금 더 키우는 게 좋겠습니다. 창의 가장자리와 프레임이나 위젯과의 거리를 조절할 때 grid 명령의 padx(좌우)와 pady(상하) 옵션을 사용합니다. 그래서 이렇게 수정하였습니다.
frame .f1
label .f1.l1 -text "수식:" -font {fixed 10}
entry .f1.e1 -textvariable expression -font {fixed 10}
label .f1.l2 -text "결과:" -font {fixed 10}
entry .f1.e2 -textvariable result -font {fixed 10}
frame .f2
button .f2.b1 -text "계산하기" -width 7 -font {fixed 10} -command {
if [catch {expr $expression}] {
tk_messageBox -message "정확히 입력해 주십시오."
} else {
set result [expr $expression]
}
}
button .f2.b2 -text "지우기" -width 7 -font {fixed 10} \
-command {set expression ""; set result ""}
grid .f1 -padx 10 -pady 5
grid .f1.l1 .f1.e1
grid .f1.l2 .f1.e2
grid .f2 -padx 10 -pady 5
grid .f2.b1 .f2.b2 -padx 5
그럼 이렇게 보입니다.
그런데 여기서 윈도의 마우스로 윈도의 귀퉁이를 드랙하여 윈도 크기를 바꿔도 엔트리 위젯의 크기는 그대로입니다. 만약 윈도의 크기에 따라 엔트리의 크기가 달라지게 하려면 어떻게 할까요. 아래와 같이 수정하였습니다. 설명은 코드 안에 간단히 달았습니다.
# 윈도의 폭은 변동될 수 있게하고 높이는 고정시킨다
wm resizable . 1 0
frame .f1
label .f1.l1 -text "수식:" -font {fixed 10}
entry .f1.e1 -textvariable expression -font {fixed 10}
label .f1.l2 -text "결과:" -font {fixed 10}
entry .f1.e2 -textvariable result -font {fixed 10}
frame .f2
button .f2.b1 -text "계산하기" -width 7 -font {fixed 10} -command {
if [catch {expr $expression}] {
tk_messageBox -message "정확히 입력해 주십시오."
} else {
set result [expr $expression]
}
}
button .f2.b2 -text "지우기" -width 7 -font {fixed 10} \
-command {set expression ""; set result ""}
# -sticky ew 옵션으로 첫번째 프레임의 좌우 폭을 윈도크기에 꽉 차게 한다
grid .f1 -sticky ew -padx 10 -pady 5
# -sticky ew 옵션으로 엔트리의 폭을 첫번째 프레임에 꽉 차게 한다
grid .f1.l1 .f1.e1 -sticky ew
grid .f1.l2 .f1.e2 -sticky ew
grid .f2 -padx 10 -pady 5
grid .f2.b1 .f2.b2 -padx 5
# 첫번째와 두번째 프레임이 메인 윈도의 첫번째 칼럼에 해당한다
# 이것들을 윈도 크기에 따라 달라질 수 있게 한다
# 0은 첫번째, 1은 두번째를 의미한다
grid columnconfigure . 0 -weight 1
# 엔트리가 첫번째 프레임의 두번째 칼럼에 해당한다
# 이것들을 윈도 크기에 따라 달라질 수 있게 한다
grid columnconfigure .f1 1 -weight 1
이렇게 한 후에도 겉모습은 비슷하지만 윈도의 창의 크기를 바꾸면 엔트리의 크기도 따라서 달라집니다. 마지막으로 엔트리를 위아래가 아니라 왼쪽과 오른쪽에 배치한 후 원래의 크기를 2:1로 하고 크기가 변화할 때도 변화하는 정도를 2:1로 하려면 어떻게 할까요?
wm resizable . 1 0
frame .f1
label .f1.l1 -text "수식:" -font {fixed 10}
entry .f1.e1 -textvariable expression -width 10 -font {fixed 10}
label .f1.l2 -text "결과:" -font {fixed 10}
entry .f1.e2 -textvariable result -width 5 -font {fixed 10}
frame .f2
button .f2.b1 -text "계산하기" -width 7 -font {fixed 10} -command {
if [catch {expr $expression}] {
tk_messageBox -message "정확히 입력해 주십시오."
} else {
set result [expr $expression]
}
}
button .f2.b2 -text "지우기" -width 7 -font {fixed 10} \
-command {set expression ""; set result ""}
grid .f1 -sticky ew -padx 10 -pady 5
grid .f1.l1 .f1.e1 .f1.l2 .f1.e2 -sticky ew
grid .f1.l2 .f1.e2 -sticky ew
grid .f2 -padx 10 -pady 5
grid .f2.b1 .f2.b2 -padx 5
# 첫번째와 두번째 프레임이 메인 윈도의 첫번째 칼럼에 해당한다
# 이것들을 윈도 크기에 따라 달라질 수 있게 한다
# 0은 첫번째, 1은 두번째를 의미한다
grid columnconfigure . 0 -weight 1
# 수식이 들어갈 엔트리가 첫번째 프레임의 두번째 칼럼에 해당한다
# 이것들을 윈도 크기에 따라 달라질 수 있게 한다
# -weight 2 옵션으로 -weight 1 옵션을 준 엔트리보다 2배 변동되게 한다
grid columnconfigure .f1 1 -weight 2
# 결과가 들어갈 엔트리가 첫번째 프레임의 네번째 칼럼에 해당한다
grid columnconfigure .f1 3 -weight 1
이렇게 하면 이렇게 보이게 됩니다.
다음에 시간이 되고 마음이 동하면 위에서 설명한 내용에다 스크롤 바가 부착된 예와 윈도 크기를 그대로 둔 상태에서 두 위젯의 크기를 동시에, 서로 반비례하도록 조정하게 하는 예를 설명하겠습니다.
grid 명령 사용의 실제 2
이번엔 스크롤바가 부착되어 있는 텍스트 위젯을 만들어 보겠습니다. 텍스트 위젯의 아래엔 좌우 스크롤바, 오른쪽엔 상하 스크롤바가 달립니다.
text .t -width 40 -height 12 -xscrollcommand ".x set" -yscrollcommand ".y set"
scrollbar .x -orient horizontal -command ".t xview"
scrollbar .y -orient vertical -command ".t yview"
grid .t .y
grid .x
이렇게 하면 이렇게 보입니다.
스크롤바를 텍스트 위젯의 크기에 맞게 꽉 차게 늘려야 합니다. 좌우로 늘릴 때는 "-sticky ew" 옵션을, 상하로 늘릴 때는 "-sticky ns", 상하좌우로 늘릴 때는 "-sticky news" 옵션을 사용합니다. 윈도의 크기를 변동시켰을 때 어떤 위젯을 얼마만큼 같이 변동시킬 것인가는 grid columnconfigure 또는 rowconfigure 명령으로 지정해 줍니다.
text .t -width 40 -height 12 -xscrollcommand ".x set" -yscrollcommand ".y set"
scrollbar .x -orient horizontal -command ".t xview"
scrollbar .y -orient vertical -command ".t yview"
# -sticky 옵션을 사용하여 지정된 방향으로 꽉 차게 만든다
grid .t .y -sticky news
grid .x -sticky ew
# 텍스트 위젯은 메인 윈도의 첫번째 칼럼에 해당함과 동시에
# 첫번째 로(행)에 해당한다
# grid columnconfigure 또는 rowconfigure 명령에서
# 0은 첫번째, 1은 두번째를 의미한다
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
그러면 이렇게 보입니다. 창의 크기를 변동시키면 위젯의 크기도 변합니다.
이번엔 스크롤바가 부착된 텍스트위젯을 좌우에 두 개로 놓고 그 사이에 막대기를 두어서 이 막대기를 움직임으로써
두 텍스트위젯의 크기를 동시에 상대적으로 조절할 수 있게 해 보겠습니다. 이때 사용하는 명령이 panedwindow 명령입니다. 이것을 만드는 과정을 이렇게 정리해 볼 수 있겠습니다.
먼저 panedwindow 명령으로 .pw 위젯을 만든 후, .pw 내에서 왼쪽에 놓일 .pw.lt 위젯을 만들고 텍스트 위젯 등을 그 안에 넣고, 마찬가지로 .pw의 오른쪽에 놓일 .pw.rt 위젯을 구성합니다. 그 후 ".pw add ..." 명령으로 .pw 안에 .pw.lt와 .pw.rt를 넣습니다.
# 윈도 .pw를 만든다
panedwindow .pw -orient horizontal
frame .pw.lt
text .pw.lt.t -width 40 -height 12 -xscrollcommand ".pw.lt.x set" -yscrollcommand ".pw.lt.y set"
scrollbar .pw.lt.x -orient horizontal -command ".pw.lt.t xview"
scrollbar .pw.lt.y -orient vertical -command ".pw.lt.t yview"
frame .pw.rt
text .pw.rt.t -width 40 -height 12 -xscrollcommand ".pw.rt.x set" -yscrollcommand ".pw.rt.y set"
scrollbar .pw.rt.x -orient horizontal -command ".pw.rt.t xview"
scrollbar .pw.rt.y -orient vertical -command ".pw.rt.t yview"
# .pw를 놓는다
grid .pw -sticky news
grid .pw.lt.t .pw.lt.y -sticky news
grid .pw.lt.x -sticky ew
grid .pw.rt.t .pw.rt.y -sticky news
grid .pw.rt.x -sticky ew
# 메인 윈도의 첫번째 칼럼과 로에 해당하는 .pw를
# 윈도 크기에 따라 달라질 수 있게 한다
grid columnconfigure . 0 -weight 1
# 메인 윈도의 첫번째 로에 해당하는 .pw의 크기를 달라질 수 있게한다
grid rowconfigure . 0 -weight 1
# .pw 위젯의 첫번째 칼럼에 해당하는 .pw.lt의 크기를 달라질 수 있게한다
grid columnconfigure .pw 0 -weight 1
# .pw 위젯의 두번째 칼럼에 해당하는 .pw.rt의 크기를 달라질 수 있게한다
grid columnconfigure .pw 1 -weight 1
# .pw 위젯의 첫번째 로에 해당하는 .pw.lt와 .pw.rt의 크기를 달라질 수 있게한다
grid rowconfigure .pw 0 -weight 1
# .pw.lt 위젯의 첫번째 칼럼에 해당하는 .pw.lt.t의 크기를 달라질 수 있게한다
grid columnconfigure .pw.lt 0 -weight 1
# .pw.lt 위젯의 첫번째 로에 해당하는 .pw.lt.t의 크기를 달라질 수 있게한다
grid rowconfigure .pw.lt 0 -weight 1
# .pw.rt 위젯의 첫번째 칼럼에 해당하는 .pw.rt.t의 크기를 달라질 수 있게한다
grid columnconfigure .pw.rt 0 -weight 1
# .pw.rt 위젯의 첫번째 로에 해당하는 .pw.rt.t의 크기를 달라질 수 있게한다
grid rowconfigure .pw.rt 0 -weight 1
# .pw.lt와 .pw.rt를 .pw 안에 넣는다
.pw add .pw.lt
.pw add .pw.rt
그럼 이렇게 보이게 됩니다.
마지막으로 사전처럼 왼쪽에 엔트리와 리스트박스, 오른쪽에 텍스트위젯이 놓이는 예를 보여 드리겠습니다. 앞서 나온 내용을 이용한 것이므로 설명은 생략합니다.
panedwindow .pw -orient horizontal
frame .pw.lt
entry .pw.lt.e
listbox .pw.lt.lb -xscrollcommand ".pw.lt.x set" -yscrollcommand ".pw.lt.y set"
scrollbar .pw.lt.x -orient horizontal -command ".pw.lt.lb xview"
scrollbar .pw.lt.y -orient vertical -command ".pw.lt.lb yview"
frame .pw.rt
text .pw.rt.t -yscrollcommand ".pw.rt.y set"
scrollbar .pw.rt.y -orient vertical -command ".pw.rt.t yview"
grid .pw -sticky news
grid .pw.lt.e - -sticky ew
grid .pw.lt.lb .pw.lt.y -sticky news
grid .pw.lt.x x -sticky ew
grid .pw.rt.t .pw.rt.y -sticky news
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
grid columnconfigure .pw 0 -weight 1
grid rowconfigure .pw 0 -weight 1
grid columnconfigure .pw.lt 0 -weight 1
grid rowconfigure .pw.lt 1 -weight 1
grid columnconfigure .pw.rt 0 -weight 1
grid rowconfigure .pw.rt 0 -weight 1
.pw add .pw.lt
.pw add .pw.rt
이 코드의 실행화면은 이렇습니다.