Tck/Tk レイアウト管理

ホーム   目次


Tcl/Tkでは、ウィンドウにウィジェット(GUI 部品)をレイアウトするために、place、pack、gridという3つの方法が用意されています。

placeの使用

placeでは、ウィジェットに対して、配置するウィンドウのx座標とy座標を指定して、配置します。

サンプルで使用する画像はここからダウンロードできます。解凍した img フォルダをコードファイルと同じディレクトリに置いてください。

Linuxをお使いの場合は、次のようにして、Img パッケージをインストールしてください。(macOSやWindowsでActiveTcl 8.6をインストールした場合はこの作業は必要ありません)

sudo apt-get install libtk-img

absolute.tcl


package require Img

oo::class create Example {
    constructor {} {
        my initUI
    }
    method initUI {} {
        wm title . 絶対配置
        frame .fr -background #333
        pack .fr -fill both -expand 1
        
        image create photo img1 -file img/valley.jpg
        label .fr.lbl1 -image img1
        place .fr.lbl1 -x 20 -y 20
        
        image create photo img2 -file img/waterfall.jpg
        label .fr.lbl2 -image img2
        place .fr.lbl2 -x 40 -y 160
        
        image create photo img3 -file img/precipice.jpg
        label .fr.lbl3 -image img3
        place .fr.lbl3 -x 170 -y 50
    }
}

wm geometry . 300x280+300+300
set e [Example new]

コード説明

package require Img

JPGファイルを使用するために Img パッケージを読み込みます。

frame .fr -background #333

frame コマンドでフレームを作成します。フレームはウィジェットを配置するための台座になるウィジェットです。.fr はルートウィンドウに fr という名前のフレームを作ることを意味します。そして、-background オプションでフレームの色を ♯333 (濃いグレー) に設定しています。

pack .fr -fill both -expand 1

pack コマンドもレイアウトコマンドの一つです。ここでは .fr に対して、x軸とy軸の両方向 (-fill   both) に、広がる (-expand   1)ことを指定しています。

image create photo img1 -file img/valley.jpg

JPEファイルから写真イメージオブジェクトを作成しています。

label .fr.lbl1 -image img1

ラベルを作成して、イメージとして、先ほど作成した写真イメージオブジェクトを設定しています。ラベルはテキストやイメージを含めることができます。ラベルの名前が .fr.lbl1 になっていることに注意してください。これは、ルートウィンドウのfrフレームにlbl1というラベルを作ることを意味しています。

place .fr.lbl1 -x 20 -y20

place コマンドで .fr.lbl1 をルートウィンドウのx座標20、y座標20に配置しています。

ウィンドウを最大化してレイアウトがどうなるか見てください。

packの使用

pack コマンドは、レイアウトを、fillオプション、expandオプション、sideオプションで指定します。

次の例では、2つのボタンをpackコマンドを使って、ウィンドウの右下に配置しています。

buttons.tcl


oo::class create Example {
    constructor {} {
        my initUI
    }
    method initUI {} {
        wm title . Buttons
        
        frame .fr
        pack .fr -fill both -expand 1
        
        frame .fr.pnl
        pack .fr.pnl -fill both -expand 1
        
        ttk::button .fr.cb -text Close -command exit
        pack .fr.cb -padx 5 -pady 5 -side right
        ttk::button .fr.ok -text OK
        pack .fr.ok -side right
    }
}

wm geometry . 300x200+300+300
set e [Example new]

コード説明

frame .fr.pnl
pack .fr.pnl -fill both -expand 1

最初の .fr フレームの上にさらに .pnl というフレームを作っています。

ttk::button .fr.cb -text Close -command exit
pack .fr.cb -padx 5 -pady 5 -side right

最初の .fr フレームの上にボタン .cb を作成します。そしてそのボタン .cb を pack コマンドの -sideオプションを使って right (右)に配置しています。上下の配置は、最初の .fr フレームが最大限に広がるように設定していますので、.cb は下に押し下げられます。

-padx オプションで .cb ボタンの左右に5ピクセルの空間を作っています。同様に、-pady オプションで .cb ボタンの上下に5pクセルの空間を作っています。

pack .fr.ok -side right

.ok ボタンも -side オプションで右側に配置しています。-side left と指定するとウィンドウの左側に表示されます。-padx は指定しません。-pady は、.cb ボタンのレイアウトに影響されることになります。

ウィンドウを最大化してレイアウトがどうなるか見てください。

packの応用

次の例では pack コマンドを使って、もう少し実用的なレイアウトを作成します。

review.tcl


oo::class create Example {
    constructor {} {
        my initUI
    }
    method initUI {} {
        wm title . 書評
        
        frame .fr1
        pack  .fr1 -fill x
        label .fr1.lbl1 -text 題名 -width 6
        pack  .fr1.lbl1 -side left -padx 5 -pady 5
        entry .fr1.ent1
        pack  .fr1.ent1 -fill x -padx 5 -expand 1
        
        frame  .fr2
        pack  .fr2 -fill x
        label .fr2.lbl2 -text 著者 -width 6
        pack  .fr2.lbl2 -side left -padx 5 -pady 5
        entry .fr2.ent2
        pack  .fr2.ent2 -fill x -padx 5 -expand 1
        
        frame .fr3
        pack  .fr3 -fill both -expand 1
        label .fr3.lbl3 -text 書評 -width 6
        pack  .fr3.lbl3 -side left -anchor n -padx 5 -pady 5
        text  .fr3.txt
        pack  .fr3.txt -fill both -padx 5 -pady 5 -expand 1
        
    }
}

wm geometry . 300x300+300+300
set e [Example new]

コード説明

pack .fr -fill x

-fill x でx (横)方向のみに広がることを指定しています。

label .fr1.lbl1 -text 題名 -width 6

-width 6 で、ラベルの横幅を 6 に設定しています。この設定値は一応文字数ということになっています。

entry .fr1.ent1

entry コマンドは、文字列を1行だけ入力できる、エントリーウィジェットを作成します。

pack .fr3.lbl3 -side left -anchor n -padx 5 -pady 5

pack コマンドの -anchor オプションはウィジェットの位置を固定します。ここでは n (north、北)を指定して、上に固定するようにしています。

text .fr3.txt

text コマンドは、文字列を複数行入力できるテキストウィジェットを作成します。

gridの使用

grid レイアウトはウィジェットを格子状に配置します。ここではサンプルとして、実際の機能はありませんが、電卓のレイアウトを作ってみようと思います。

calculator.tcl


oo::class create Example {
    constructor {} {
        my initUI
    }
    method initUI {} {
        
        wm title . 計算機
        
        frame .fr -padx 5 -pady 5
        pack  .fr -fill both -expand 1
        
        ttk::style configure TButton -widht 8 -height 8 \
        -font "serif 10"
        
        grid columnconfigure .fr 0 -pad 3
        grid columnconfigure .fr 1 -pad 3
        grid columnconfigure .fr 2 -pad 3
        grid columnconfigure .fr 3 -pad 3
        
        grid rowconfigure .fr 0 -pad 3
        grid rowconfigure .fr 1 -pad 3
        grid rowconfigure .fr 2 -pad 3
        grid rowconfigure .fr 3 -pad 3
        grid rowconfigure .fr 4 -pad 3
         
        entry .fr.ent
        grid  .fr.ent -columnspan 4 -sticky we
        
        ttk::button .fr.cls -text Cls
        grid .fr.cls -row 1 -column 0
        ttk::button .fr.bck -text Back
        grid .fr.bck -row 1 -column 1
        ttk::button .fr.lbl
        grid .fr.lbl -row 1 -column 2
        ttk::button .fr.clo -text Close
        grid .fr.clo -row 1 -column 3
        
        ttk::button .fr.sev -text 7
        grid .fr.sev -row 2 -column 0
        ttk::button .fr.eig -text 8
        grid .fr.eig -row 2 -column 1
        ttk::button .fr.nin -text 9
        grid .fr.nin -row 2 -column 2
        ttk::button .fr.div -text /
        grid .fr.div -row 2 -column 3
        
        ttk::button .fr.fou -text 4
        grid .fr.fou -row 3 -column 0
        ttk::button .fr.fiv -text 5
        grid .fr.fiv -row 3 -column 1
        ttk::button .fr.six -text 6
        grid .fr.six -row 3 -column 2
        ttk::button .fr.mul -text *
        grid .fr.mul -row 3 -column 3
        
        ttk::button .fr.one -text 1
        grid .fr.one -row 4 -column 0
        ttk::button .fr.two -text 2
        grid .fr.two -row 4 -column 1
        ttk::button .fr.thr -text 3
        grid .fr.thr -row 4 -column 2
        ttk::button .fr.mns -text -
        grid .fr.mns -row 4 -column 3
        
        ttk::button .fr.zer -text 0
        grid .fr.zer -row 5 -column 0
        ttk::button .fr.dot -text .
        grid .fr.dot -row 5 -column 1
        ttk::button .fr.equ -text =
        grid .fr.equ -row 5 -column 2
        ttk::button .fr.pls -text +
        grid .fr.pls -row 5 -column 3
    }
}

wm geometry . +300+300
set e [Example new]

コード説明

ttk::style configure TButton -widht 8 -height 8 \
-font "serif 10"

ttk::button のスタイルを設定しています。1行目末尾の \ (バックスラッシュ)は、行継続文字です。コマンドは1行で書かなければなりませんが、複数行にまたがる場合は、行継続文字を使用して、行が続いていることを Tcl に知らせます。

grid columnconfigure .fr 0 -pad 3

これから使うgridレイアウトの0番目の列の左右に3ピクセルの空白を設定しています。
gridレイアウトの列番号は0から始まります。

このコードを記述しなくても、セル間の空白がなくなるだけで、アプリケーションは正常に動作します。また、gridを使用する前にこのコードを書いておくという決まりでもありません。実際にこのコードをソースファイルの最後に記述しても、アプリケーションは正常に動作します。

なお、このコードによってgridの列数が決まるわけではありません。このコードが実際の列数より少ない場合は、空白が設定されないだけです。実際の列数より多い場合は無視されるだけです。

grid rowconfigure .fr 0 -pad 3

これから使うgridレイアウトの0番目の行の上下に3ピクセルの空白を設定しています。
gridレイアウトの行番号は0から始まります。

このコードを記述しなくても、セル間の空白がなくなるだけで、アプリケーションは正常に動作します。また、gridを使用する前にこのコードを書いておくという決まりでもありません。実際にこのコードをソースファイルの最後に記述しても、アプリケーションは正常に動作します。

なお、このコードによってgridの行数が決まるわけではありません。このコードが実際の行数より少ない場合は、空白が設定されないだけです。実際の行数より多い場合は無視されるだけです。

grid .fr.ent -columnspan 4 -sticky we

TkのGUIフレームワークではgridの行数と列数を前もって設定しておくことはしません。gridの行数と列数は、その後の文脈によって決定されます。

また、最初に配置されるウィジェットは -row 0 -columen 0に決まっていますので、これらのオプションを省略することができます。

「-columnspan   4」で、このウィジェットが4列にまたがることを設定しています。

「-sticky   we」で、このウィジェットがwest east、つまり左右に広がることを指定しています。Tkではgridに配置されたウィジェットがそのセルを埋めるように自動的に広がることはありません。

ttk::button .fr.cls -text Cls
grid .fr.cls -row 1 -column 0

ボタン .fr.cls は、1行目 (表示上は2列目) の 0列目 (表示上は1列目) に表示されます。

gridの応用

この章の最後として、gridを使ってもう少し柔軟なレイアウトを作ってみようと思います。

windows.tcl


oo::class create Example {
    constructor {} {
        my initUI
    }
    method initUI {} {
        wm title . Windows
        frame .fr -padx 5 -pady 5
        pack  .fr -fill both -expand 1
        
        grid columnconfigure .fr 1 -weight 1
        grid columnconfigure .fr 3 -pad 7
        grid rowconfigure .fr 3 -weight 1
        grid rowconfigure .fr 5 -pad 7
        
        label .fr.lbl -text Windows
        grid .fr.lbl -sticky w -pady 4 -padx 5
        
        text .fr.txt
        grid .fr.txt -row 1 -column 0 -columnspan 2 \
                -rowspan 4 -padx 5 -sticky ewsn
        
        ttk::button .fr.act -text Activate
        grid .fr.act -row 1 -column 3
        
        ttk::button .fr.cls -text Close
        grid .fr.cls -row 2 -column 3 -pady 4
        
        ttk::button .fr.hlp -text Help
        grid .fr.hlp -row 5 -column 0 -padx 5
        
        ttk::button .fr.ok -text OK
        grid .fr.ok -row 5 -column 3
    }
}

wm geometry . 350x300+300+300
set e [Example new]

コード説明

grid columnconfigure .fr 1 -weight 1 ... grid rowconfigure .fr 3 -weight 1

weight オプションで2番目の列と4番目の行を拡張可能にしています。この行と列のセルは、ウィンドウが広がると、このセルも広がることになります。

grid .fr.lbl -sticky w -pady 4 -padx 5

ラベル .fr.lbl は,「sticky   w」により west (左)に貼りつくことになります。

text .fr.txt
grid .fr.txt -row 1 -column 0 -columnspan 2 \
-rowspan 4 -padx 5 -sticky ewsn

テキストウィジェット .fr.txt を作成しています。このテキストウィジェットは2行目の1列目から5行目の3列目にまでまたがって占有しています。そしてewsnの4つの側面すべてに張り付いています。先に、4行目と2列目のセルは拡大可能に設定していますので、ウィンドウが拡大すれば、このテキストウィジェットも拡大することになります。

ウィンドウを最大化してレイアウトがどう変更されるか見てください。


14494 visits
Posted: Dec. 17, 2018
Update: Dec. 18, 2018

ホーム   目次   ページトップ