본문으로 바로가기

테이블 위젯 Tktable

category 카테고리 없음 2025. 8. 7. 11:46

Tktable은 table 표시를 위한 위젯입니다. table 위젯은 테이블 형식으로 2차원 데이터를 표시하고 편집할 수 있는 위젯으로, 표준 Tk에서는 쉽게 할 수 없는 데이터 시트 조작을 구현할 수 있습니다.

package require Tktable

set glob "./*"; set files [glob -nocomplain $glob]
set files [glob -nocomplain $glob]

set tabtab(0,1) "Name"
set tabtab(0,2) "Type"
set tabtab(0,3) "Mode"
set tabtab(0,4) "Time"

set y 1 
foreach path $files {
    file stat $path a
    set tabtab($y,1) [file tail $path]
    set tabtab($y,2) $a(type)
    set tabtab($y,3) [string range [format %o $a(mode)] 2 end]
    set tabtab($y,4) [clock format $a(mtime) -format "%Y-%m-%d %H:%M"]
    incr y
}

table .t -rows $y -cols 4 -variable tabtab -titlerows 1 -titlecols 0 \
  -roworigin 0 -colorigin 1 -font {Helvetica 12 normal}

pack .t -fill both -expand true
bind . <Button-3> exit

table 위젯은 table 커맨드로 생성합니다. -rows는 행의 개수, -cols는 열의 개수입니다. -rows의 값은 테이블의 위젯의 높이(height)와는 전혀 상관없고, 후술 할 -variable의 배열 변수가 가지고 있는 행 데이터의 개수를 그대로 지정해야 합니다.

 

-variable은 첫 번째 중요한 옵션으로 배열의 변수 이름을 지정합니다. 2차원 데이터이기 때문에 (행(y), 열(x))의 2차원 배열 변수로 지정해야 합니다. 셀 개수만큼 모두 값을 대입할 필요는 없고, 값을 없다면 셀은 비워두어도 괜찮습니다.

 

-titlerows는 표의 상단에, -titlecols는 표의 왼쪽 끝에 표시할 제목 셀의 개수입니다. 스크린샷과 예제 코드를 비교해 보면 -titlerows가 1이므로 맨 위에 제목 행이 한 줄 있고, -titlecols가 0이므로 맨 왼쪽에 제목 행이 없습니다.

 

-roworigin과 -colorigin으로 배열 변수의 행, 열의 시작에 대한 옵션을 지정합니다. 즉, 이 예제의 경우 왼쪽 상단은 'tabtab(0,1)'이므로 -roworigin은 0, -colorigin은 1을 지정하고 있습니다. 마지막으로 -font 등 일반 Tk 위젯이 가지고 있는 많은 옵션은 table에서도 사용할 수 있습니다.

 

여기까지의 설명으로 일단 table 위젯으로 파일 목록을 표시할 수 있게 되었습니다. 기본적으로 제목 셀은 편집할 수 없지만, 제목이 아닌 셀은 키 입력으로 편집할 수 있습니다. Excel처럼 셀을 편집할 수 있지만 키보드를 여러 번 두드리다 보면, 처음에는 조금 당황스러울 수 있습니다. 왜냐하면 아마도 Backspace로 삭제할 수는 있지만, 커서 키로 셀 내 문자열 사이를 커서를 움직일 수는 없는 건 문제가 있다고 생각하실 것입니다. 셀 내 입력 커서 이동은 CTRL+커서 좌우키로 할 수 있습니다. 기본 키 바인딩이 조금 까다롭고 엑셀과 전혀 달라 헷갈릴 수 있습니다. 아래는 매뉴얼의 '기본 키 바인딩'입니다.

 

마우스 왼쪽 버튼 클릭 클릭한 셀을 활성화합니다. 이미 활성화된 셀을 클릭한 경우, 커서와 가장 가까운 위치에 입력 커서를 표시합니다.
HOME 왼쪽 상단 셀로 이동
END 오른쪽 하단 셀로 이동
CTRL+HOME 왼쪽 상단의 셀로 이동하여 해당 셀을 활성화합니다.
CTRL+END 오른쪽 하단의 셀로 이동하여 해당 셀을 활성화합니다.
SHIFT+CTRL+HOME 왼쪽 상단 셀까지 선택 범위를 넓히기
SHIFT+CTRL+END 오른쪽 하단 셀까지 선택 범위를 넓히기
방향키 활성 셀 이동하기
SHIFT+방향키 커서 키의 방향으로 선택 범위 확대
CTRL+좌우방향키 셀 내 입력 커서를 좌우로 이동하기
CTRL+/ 모든 셀을 선택 상태로 만들기
CTRL+\ 모든 셀을 비선택 상태로 만들기 
BACKSPACE 입력 커서 앞의 문자 삭제하기 
DELETE 입력 커서 뒤의 문자 삭제하기 
ESCAPE 편집을 취소하고 셀의 원래 값을 다시 불러오기 
CTRL+A 입력 커서 앞쪽으로 이동하기 
CTRL+E 입력 커서 뒤쪽으로 이동하기
CTRL+- 현재 활성화된 셀의 열 너비 줄이기 
CTRL+= 현재 활성화된 셀의 열 너비 늘리기

 

키 바인딩이 엑셀과 전혀 다른 걸 보실 수 있습니다. 아래와 같이 변경하면 조금이라도 엑셀 키 바인딩에 가까워질 수 있습니다.

bind Table <Tab>        {::tk::table::MoveCell %W 0 1}
bind Table <Shift-Tab>  {::tk::table::MoveCell %W 0 -1}
bind Table <Return>     {::tk::table::MoveCell %W 1 0}
bind Table <Shift-Return> {::tk::table::MoveCell %W -1 0}
bind Table <Control-b>  {%W icursor [expr {[%W icursor]-1}]}
bind Table <Control-f>  {%W icursor [expr {[%W icursor]+1}]}
bind Table <Left>       {%W icursor [expr {[%W icursor]-1}]; break}
bind Table <Right>      {%W icursor [expr {[%W icursor]+1}]; break}

이전의 표에는 없지만 -selectmode가 single이나 extended인 경우 CTRL+C로 선택한 셀의 값을 클립보드로 복사할 수 있고, CTRL+V로 클립보드의 값을 table에 붙여 넣기를 할 수 있습니다.

이것저것 다 제쳐두고도 예제의 결과물은 상당히 아쉽습니다. 우선 Time 열의 폭이 너무 좁고, 그리고 파일명은 중앙 정렬이 아닌 왼쪽 정렬을 보기 좋을 거 같습니다. 그리고 제목 줄의 배경색을 바꾸고, 제목 문자열은 굵은 글씨로 표시하고 싶습니다. 그래서 예제를 이것저것 수정해 봅니다.

# 4번째 열의 너비를 16 크기로 설정
.t width 4 16

# 제목 줄의 배경색, 글자색, 글꼴을 설정
.t tag configure title -bg "midnightblue" -fg "white" -font {Helivetica 12 bold}

# 1열의 0행(제목행)을 제외한 모든 셀을 왼쪽 정렬.
.t tag row row0 0
.t tag col col1 1
.t tag configure col1 -anc w
.t tag configure row0 -anc center

# 3열의 각 셀을 groove로 둘러싸고 편집할 수 없도록함.
.t tag col col3 3
.t tag configure col3 -rel groove -bd 3 -state disabled

table 위젯에도 표준 Tk 위젯과 마찬가지로 수많은 위젯 서브 커맨드가 있습니다. 특정 열의 너비를 변경하려면 width 서브  커맨드를, 높이를 변경하려면 height 서브 커맨드를 사용합니다. width의 값은 현재 글꼴의 글자 수입니다. 너비나 높이 이외의 속성을 변경하려면 태그라는 것을 정의해야 합니다. 기본 정의된 4개의 태그가 있는데, active, flash, sel, title이며, 예제에서 사용하는 title은 그중 하나이며, 제목 셀 전체를 의미합니다. 여기서는 이 태그에 tag configure 위젯 명령을 사용하여 배경색, 글자색, 글꼴을 변경하고 있습니다. 폰트에서 bold로 지정하여 굵게 표시하고 있습니다.

 

그 외의 지정 열이나 행에 태그를 만들려면 tag col, tag row 서브  커맨드를 사용합니다. 그리고 만든 태그에 대해 tag configure로 속성을 변경합니다. -anc는 -anchor의 줄임말로 정렬 방법을 지정합니다. 위 예제에서는 1열을 왼쪽 정렬하고 있는데, 이때 1열의 제목 셀도 왼쪽 정렬이 되므로, 그 위에 겹쳐서 1행을 가운데 정렬하고 있습니다.

package require Tktable

set glob "./*"; set files [glob -nocomplain $glob]
set files [glob -nocomplain $glob]

set tabtab(0,1) "Name"
set tabtab(0,2) "Type"
set tabtab(0,3) "Mode"
set tabtab(0,4) "Time"

set y 1 
foreach path $files {
    file stat $path a
    set tabtab($y,1) [file tail $path]
    set tabtab($y,2) $a(type)
    set tabtab($y,3) [string range [format %o $a(mode)] 2 end]
    set tabtab($y,4) [clock format $a(mtime) -format "%Y-%m-%d %H:%M"]
    incr y
}

table .t -rows $y -cols 5 -colwidth 6 -rowheight -40 \
  -variable tabtab -titlerows 1 -titlecols 1 \
  -roworigin 0 -colorigin 0 -font {Helvetica 12 normal} \
  -selectmode extended -cursor arrow

.t width 1 16
.t width 2 9
.t width 4 16
.t tag configure title -bg "midnightblue" -fg "white" -font {Helivetica 12 bold}

.t tag row row0 0
.t tag col col1 1
.t tag configure col1 -anc w
.t tag configure row0 -anc center

.t tag col col3 3
.t tag configure col3 -rel groove -bd 3 -state disabled

bind .t <Double-1> {
    set c [%W curselection]
    tk_messageBox -message $c
}

for {set i 1} {$i<=[expr [.t cget -rows]-1]} {incr i} {
    checkbutton .t.ck$i
    .t window configure $i,0 -window .t.ck$i
}

pack .t -fill both -expand true
bind . <Button-3> exit

위 예제와 같이 table 위젯의 셀 안에 다른 위젯을 삽입할 수도 있습니다. 이를 위해 window configure 서브  커맨드를 사용합니다. 그 인수는 '행, 열'로 위치를 지정하고, -window로 삽입할 위젯을 지정합니다. 단, 셀에 위젯을 삽입하면 기본적으로 셀의 높이가 부족하기 때문에 table의 -width와 -height로 기본 셀의 너비와 높이를 지정하고 있습니다. Tktable은 이 너비와 높이를 지정하는 방식이 상당히 특이한데, 양수로 지정하면 문자 수(높이의 경우 단수), 음수로 지정하면 픽셀의 의미가 됩니다. 즉, 14로 지정하면 14글자, -140으로 지정하면 140픽셀의 의미가 됩니다.

 

또한 현재 선택된 셀을 확인하려면 curselection이라는 서브  커맨드를 사용합니다. 이 서브  커맨드는 선택된 셀의 위치를 “행, 열” 형식의 문자열로 반환합니다. 이 행과 열의 인덱스는 제목 행과 일반 행의 구분 없이 왼쪽 상단 셀을 기준점으로 한 셀의 위치로 반환되는데, -roworigin, -colorigin 옵션에 따른 보정된 값을 받습니다.