CUIの引数設定をGUI化
- 四捨五入の話を挟みましたが"PerlでGUIプログラミング"レポート第2回目です。1回目へのリンクは[こちら]です。前回は日本語の扱いなど準備に相当する内容でしたが、今回からプログラミングに入っていきます。
- プロのソフトエンジニアではない我々が作るツールは繰り返し作業をコンピュータで効率化することが主目的のため、コマンドプロンプトやバッチファイルで引数/オプション設定するCUI(Character User Interface)で十分です。しかしIT化が進んでいない(*1)環境では、CUIによるデータ設定を難しいと感じるメンバが多数派です。
- そのため入力設定や出力を確認するGUI(Graphical User Interface)を必要としますが、プログラム言語の入門本を読んでいきなりGUIツールを作ることはできません(*2)。ですが、このままだとIT化が進まない負のスパイラルに入るので、GUIツール作成の敷居を下げるのが本レポートの目的です。
- 先に書いたように、業務効率化の多くはCUIツールで事足りるので、GUIに必要な要素は下記のみでしょう。出力に関しては、Windowsであればstartコマンドで何とかなります。終了もWindow右上の[X]ボタンを押せば良いです。
- MainWindow: 親Window
- Label: 文字表示
- Entry: データ/設定入力欄
- Button: ツールの実行
|
|
|
- そして作成するツールには必ずCUIインタフェースも残しましょう。自動化が進むとツール同士を連結するからです。
CUIはShift_JIS/cp932コードで作成する
- 現在の方針だと、最初に作るのはCUIツールなので、日本語Windowsの文字コードであるShift_JIS/cp932でスクリプトを作成します。よってutf8プラグマは不要です。例としてサンプルコードのuse文を示します。
#!perl -w
# ==============================================================================
# 内部文字列はcp932/Shift_JISとするので use utf8; は不要
# ==============================================================================
use File::Temp qw(tempfile);
use File::Basename qw(basename);
use Getopt::Long qw(GetOptions);
use Encode qw(decode encode);
use Tk;
use strict;
そしてGUIを追加するわけですが、Tkのウィジェットはutf8のため、ウィジェットとスクリプト間のデータやり取りで文字コード変換をケアすることになります。
Figure 2: Tk widghtとのコード変換処理
それでは各ウィジェットの使い方を見ていきましょう。
サンプルコードについて
- サンプルとして指定文字列をHTMLに変換するツールを作ってみます。※[コード表示(別タブ)] / [ダウンロード]
Figure 3: サンプルツールGUI
- サンプルコードはコマンドラインに与えられた引数を見てGUI/CUIモードを決めています。例えばエクスプローラ上でダブルクリック等すれば引数が無いのでGUIモードになります。
- サンプルコードはGUIモードとしてmode_gui($args)サブルーチンを実行します。このサブルーチン内でTkのウィジェットを設定し、GUI実行のループに入ります。
MainWindowの使い方
- 下記に示すリストはmode_gui($args)ルーチンの先頭部です。MainWindowのオブジェクトを取得後、バーに表示するツール名、使用するデフォルトフォント、Windowリサイズの設定を行っています。
sub mode_gui {
# 引数
my ($args) = @_;
# MainWindowオブジェクト取得
my $o_mw = MainWindow->new(); # オブジェクト取得
$o_mw->title(decode('cp932',$G_scrname)); # ツールタイトル(スクリプト名)
$o_mw->optionAdd('*font'=>['Meiryo UI',10]); # デフォルトフォント
$o_mw->resizable(1,0); # (width, hight) widthのみサイズ変更可能
- Tkウィジェットはutf8を扱うため、titleメソッドに文字列を与える際、decode関数でutf8に変換しています。
- optionAddメソッドでWindow全体のデフォルトフォントと文字サイズを設定します。Windowに追加されるウィジェット全てに適用されますが、ウィジェット毎にフォントを変更する場合は、ウィジェット側の-font指定で設定します。
- resizableメソッドはWindowの幅/高さの変更設定です。デフォルトは両方変更可ですが、サンプルコードでは幅(width)のみ変更可としています。
Labelウィジェットの使い方
- 文字を表示するウィジェットがLabelです。こちらもMainWindowのtitle同様にutf8へ変換して渡します。
# Labelウィジェット設定(ウィジェットへ渡すデータはデコードutf-8)
my $o_label_str = $o_mw->Label(-text=>decode('cp932','-str: 表示文字列'));
my $o_label_fname = $o_mw->Label(-text=>decode('cp932','-fname: 出力ファイル名(省略可)'));
- -font指定は入れていないので、MainWindowで設定したデフォルトフォントが適用されます。
Entryウィジェットの使い方
- 文字やデータの入力を受け付けるウィジェットがEntryです。
# Entryウィジェット設定(ウィジェットから戻るデータはデコードutf-8)
my $str_u8 = ''; # 値格納変数(utf-8想定)
my $fname_u8 = ''; # 値格納変数(utf-8想定)
my $o_entry_str = $o_mw->Entry(-textvariable=>\$str_u8, # 格納変数への参照
-width=>40);
my $o_entry_fname = $o_mw->Entry(-textvariable=>\$fname_u8, # 格納変数への参照
-width=>40);
# Entry文字初期値設定(引数からの値はcp932のため変換して渡す)
$o_entry_str ->insert(0, decode('cp932',$args->{str}));
$o_entry_fname->insert(0, decode('cp932',$args->{fname}));
- -textvaliable で入力データを格納する変数のリファレンスを与えます。引数名覚えにくいですが慣れましょう。
- -width でEntryウィジェットの表示幅を設定します。設定フォントの文字数で指定します。
- Entryウィジェットのオブジェクト定義後、insert(挿入位置, 挿入文字列)メソッドで初期値を設定します。未設定時は空文字列が初期値です。文字列はutf8へ変換して渡します。
Buttonウィジェットの使い方
- コマンド及び動作を登録するウィジェットがButtonです。
# Buttonウィジェット設定(サブルーチンリファレンスの書き方はTk::UserGuideに合わせた)
# (ウィジェットから戻るデータはデコードutf-8)
my $o_button_run = $o_mw->Button(
-text=>'run', # ボタン上のテキスト
-width=>6, # ボタンの幅(6文字)
-font=>['Meiryo UI',8], # デフォルトと異なるフォント設定
-command=>sub{ # 関数への参照を与える
run(
# モードgui指定
mode=>'gui',
# 文字変換して値を渡す
str=>encode('cp932', $str_u8),
fname=>encode('cp932', $fname_u8)
)
}
);
- -text でボタンに表示する文字列を設定します。2byte文字使用時はdecode関数によるutf8変換が必要です。
- -width でウィジェットの幅を指定します。数値は文字数で、Entryウィジェットの-widthと同じです。
- -font でウィジェットに適用するフォントを設定します。先述のMainWindowで設定したデフォルトフォント設定よりサイズを小さくしています。他のウィジェットもフォント設定をデフォルトから変更したい場合同様に記述します。
- -command でボタンを押した際の動作/コマンドを登録します。指定するのはコマンド/サブルーチンへのリファレンスですが、例に示した無名サブルーチン(sub{ ... })を利用した記述がおすすめです。
- CUI/GUI共用ツールでは、CUIのメインルーチンと同一のルーチンを登録(サンプルではrun関数)します。
- CUIはcp932/Shift_JISで動くため、メインルーチンの引数にデータを与える際、文字コード変換が必要です。それがサンプルに記述されているencode関数の役割です。
- 尚、無名ルーチン内でrun関数の前に処理を記述することもできます。
ウィジェットの配置...今回は上から順番に置くだけ
- 設定したウィジェットをMainWindow内に配置しますが今回は上から順番に置くだけです。フレーム/ウィジェット間の隙間設定、左寄せ('W'estって...)、MainWindowに合わせた伸縮を使っていますが、配置設定詳細は次回説明します(*3)。
# ウィジェット配置(上から順番に置くだけ)
my %padxy = (-padx=>8, -pady=>0); # デフォルトの(x,y)パディング値
$o_label_str ->pack(%padxy, -anchor=>'w' ); # Label(表示文字列): 左寄せ
$o_entry_str ->pack(%padxy, -fill=>'both'); # Entry(表示文字列): windowに合わせて伸びる
$o_label_fname->pack(%padxy, -anchor=>'w' ); # Label(出力ファイル名): 左寄せ
$o_entry_fname->pack(%padxy, -fill=>'both'); # Entry(出力ファイル名): windowに合わせて伸びる
$o_button_run ->pack(%padxy, -anchor=>'w', # Button(run): 左寄せ
-pady=>2 ); # 最後のウィジェットなのでy方向パディング=2
最後はGUIツールとしてLoopに突入してイベント駆動へ
- GUIの設定が終了したので、これからMainWindowを起動してループ実行に入りますが、これは下記の定型記述です。
# MainWindow実行開始
MainLoop();
最低限はこれでOK
- さあどうでしょうか。CUIツールが作成できれば、そこにシンプルなGUIを被せることが可能な状態になったでしょう。Perl/Tkで作成したツールはWindows/Linuxの両方で動作するため高い汎用性を持ちます。
- GUIは敷居の高いところもありますが、本当の意味でGUIが必要なツールは、End User Computingの範疇から完全に外れるので、我々に高いGUI構成スキルは必要ありません(*4)。
- 後は、気が向いたときにちょっとずつスキルアップすれば良いです。その流れで次回はウィジェットの配置を扱います。
|