全く実用にならないサンプルで見るTktable

Tktableは、「table」という名前のTk拡張ウィジェットを追加するライブラリです。 tableウィジェットは、表形式で2次元のデータを表示・編集することができるもので、 標準Tkではなかなかできないデータシート操作を実現できます。

Tktableはオープンソース・ソフトウェアで、 SourceForgeで無償で入手できます。 また、 Windows用のTcl/Tkバイナリ配布である ActiveTclにも同梱されています。 現在の最新版はバージョン2.10です。

スクリーンショット

package require Tktable

set glob "/home/mamemiya/tcl/*"; set files [glob -nocomplain $glob]
set files [glob -nocomplain $glob]

set tabtab(0,1) "ファイル名"
set tabtab(0,2) "タイプ"
set tabtab(0,3) "モード"
set tabtab(0,4) "編集時刻"
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
bind . <Button-3> exit

tableウィジェットはtableコマンドで作ります。ってあたりまえか。
それで、-rowsは行の数、-colsは列の数です。 ここで早くも最初の山です。ええっ2行目にして早くもとかないですから。 Tktableの道は長く険しいのではなくて、短くて超険しいだけですから(帰れ) えーとそれで、 あー -rowsの値は、 このウィジェットの縦のサイズ(つまり高さ) を行数分で指定するためのものではありません。 -heightで指定するテーブルのウィジェットとしての高さとも全然関係なく、 後述の-variableの配列変数が持っている行データの数をそのまま指定する必要があります。

-variableが最初の重要なオプションで、配列の変数の名前を指定します。 2次元のデータだからリストのリストで指定するのかと思いきや、そうではありません。 (行,列)の2次元の添字を持つ配列変数で指定するのです。 (行,列)ですから(x,y)ではなく、(y,x)となるのに注意してくださいね。 この添字はセルの数だけ全て値を代入しておく必要はなくて、 値を代入してないセルは空欄になるので大丈夫です。
そんでそんで、 -titlerowsは表の上端に、-titlecolsは表の左端に表示する見出しセルの数です。 スクリーンショットとスクリプトを見比べて頂くと、 -titlerowsが1なので上端に見出し行が1行あり、-titlecolsが0なので左端には見出し行はありません。
そんでそんでそんで、-roworiginと-coloriginが使い方次第では面白いオプションで、 配列変数の添字が行、列それぞれ何から始まるかを指定するものです。 簡単に言うと、左上隅のセルの値を持つ配列変数の添字を指定するのです。 つまり、この例は左上隅は 「tabtab(0,1)」なので-roworiginは0、-coloriginは1というわけです。 最後に-fontなど、普通のTkウィジェットが持っているオプションの多くはtableでも使えます。
これで一応tableウィジェットでファイル一覧を表示できました。 デフォルトで、見出しセルは編集できませんが、見出しでないセルはキー入力で編集できます。 MS-Excelみたいにセルが編集できるのか!と喜んでキーボードをいろいろ叩いてみると、 最初はちょっと面食らうと思います。 というのは多分、Backspaceで削ることはできるけど、 カーソルキーで文字列の間にカーソルを動かすことはできないのか!? そんなの今時、使えへんーーーー!!!! と思うことでしょう。
…実は、セル内の入力カーソルの移動はCTRL+カーソルキーの左右で行えます。 デフォルトのキーバインディングがちょっとトリッキーで、Excelとは全然違うのでまごまごチックです。 一応、マニュアルの「デフォルトのキーバインディング」を、簡単に訳してみました。

キー操 作
マウス左クリック クリックされたセルをアクティブにする。既にアクティブなセルをつついた場合は、 その震源に最も近い位置に入力カーソルを表示する
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+=現在アクティブなセルの列幅を広くする

なんじゃこりゃ?Excelと全然違うやん。
少しでもExcel伝統の動きに近づけるには? 実は捨てる神あれば拾う神あり、じゃなかった、何? Excelと違うバインディングにするTktableあれば Excelと同じバインディングあり(なんじゃそりゃ)、 そうそう、バインディングを変更すれば何とかなるのです。

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}

キー操 作
カーソルキーセル内の入力カーソルを左右に移動させる
TAB右のセルに移動
SHIFT+TAB左のセルに移動
ENTER下のセルに移動
SHIFT+ENTER上のセルに移動
CTRL+Bセル内の入力カーソルを左に移動させる
CTRL+Fセル内の入力カーソルを右に移動させる

また、先ほどの表にはありませんが、 -selectmodeがsingleやextendedの場合、 CTRL+Cキーで選択したセルの値をクリップボードにコピーすることができ、 CTRL+Vキーでクリップボードの値をTktableに貼り付けることができます。

そんでそそそそそんで、それをおいといても、まだかなり不満な出来です。 まず編集時刻の列は幅が狭すぎます。 またファイル名は中央揃えではなく左揃えにしたいのですが。 また、見出し行は背景色を変え、その見出し文字列は太字で表示したいところです。 ということであれこれ改造してみましょう。 以下はその追加分だけです。重複分を省略して地球に優しくしてみました。

スクリーンショット

# 列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とtagという2つのコマンドだけを使っています。 特定の列の幅を変更するにはwidthコマンドを、高さを変更するにはheightコマンドを使います。 widthの値は現在のフォントでの文字数(バイト数)です。 幅や高さ以外の属性を変更するには、 「タグ」 とゆーものを定義します。 最初から定義済みのタグが4つあります。active、flash、sel、titleで、 ここで使っているtitleはそのうちの1つであって、見出しセル全部という意味です。 ここではこのタグにtag configureウィジェットコマンドを使って、 背景色、文字色、フォントを変えています。フォントでboldと指定しているので、太字になってます。
それ以外の「何列目」のようなタグを作るには、tag colコマンド(列を指定)、 tag rowコマンド(行を指定)を使います。 そして作ったタグに対して、tag configureで属性を変更します。-ancは-anchorの省略形です。 この目的に使うのは-justifyではなく-anchorのようなので、要注意。
この例では、1列目を左揃えにし、それだと1列目の見出しセルも左揃えになってしまうので、 その上に重ねて1行目を中央揃えにしています。 (このサンプルでは1行目=タイトル行なので、 row0タグを作らなくても、組み込みタグtitleで指定しても同じですが…)

スクリーンショット

package require Tktable

set glob "/home/mamemiya/tcl/*"; set files [glob -nocomplain $glob]

set tabtab(0,1) "ファイル名"
set tabtab(0,2) "タイプ"
set tabtab(0,3) "モード"
set tabtab(0,4) "編集時刻"
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 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
bind . <Button-3> exit

この例のように、tableウィジェットのセルの中に別のウィジェットを埋め込むこともできます。 それには、window configureウィジェットコマンドを使います。 その引数は 「行,列」で位置を指定し、-windowで埋め込むウィジェットを指定します。 但し、セルの値とそのウィジェットに表示する値を同期的に紐付けて連動させることはできません。 それで、チェックボックスを入れるとデフォルトではセルの高さが足りないので、 tableの-widthと-heightでデフォルトのセルの幅と高さを指定しています。 Tktableはこの幅や高さの指定の仕方が結構変わっていて、 正の数で指定すると文字数(高さの場合は段数)、負の数で指定するとピクセルの意味になります。 つまり14と指定すると14文字、-140と指定すると140ピクセルの意味になるということです。 なんでかとか聞いてはなりませぬ。

また、現在選択されているセルを知るには、curselectionというウィジェットコマンドを使います。 これは、選択されているセルの位置を、"行,列"の形の文字列で返します。 この行、列のインデックスは、 見出し行・普通の行の区別なく、左上端のセルを基点としたセルの位置で返されます。 また-roworigin、-coloriginによる補正を受けます。 左上端が(0,0)でない場合、数え間違えないように注意が必要です。

拡張レビュー分室 top
(first uploaded 2005/08/24 last updated 2011/01/08, MISUMI URANO)