PerlでGUIプログラミング(1)
2022/06/26
GUIプログラムをPerlで作りたい
  • エンジニアではないメンバも含めて使用する想定のプログラム/ツールには、やはり"GUIインターフェース"を求められることが増えてきます。

  • 最も手軽にGUIツールを作る手段は、JavaScriptでブラウザを使うことかと。しかし、その場でデータを入力/表示する場合は良いのですが、ファイルを経由してデータ入出力を行う場合サーバサイドで動かす必要があるため、そもそもサーバを立てられないとこの手段は取れません。HTML5は消えちゃいましたし。

  • あとは以前扱いましたが、VBAで擬似的なGUIを表計算ソフト上に作る方法です。ExcelだけでなくCalcでも可能なので誰でも実行できますが、そもそもVBAプログラミングがつらい。

  • できれば慣れた言語にちょっと何かを追加して作りたい...私の場合慣れた言語とはPerlですが、これで手軽にGUIを作ろうとすれば、やはりTkを使うのが良いかなと思っています。

  • そこでTkの使い方を調べてみることにしました。今回は簡単なコードを書きつつ環境準備的な内容をレポートしますが...ほとんどTkのプログラムに関する話は出ません。下記内容となります。

Tkモジュールのインストールとサンプル実行
  • Strawberry PerlにしてもActive Perlにしても、このTkモジュールは標準でインストールされていないので、追加インストールする必要があります。Strawberry Perlの環境を例にすると下記のようにcpanコマンドでインストールを行います。
    • > cpan Tk
       ※ざっくり10分程度かかります...

  • Tkをインストールしたら、早速簡単なコードを入れてみましょう。下記はラベルとして "Hello, Perl/Tk World!!" を表示し、終了(Quit)ボタンを持つアプリケーションのコード(tk_test_00.pl)です(*1)
    #!perl -w
    use Tk;
    use strict;
    
    {
        my $o_wm = MainWindow->new();
    
        my $o_label_0 = $o_wm->Label(-text=>'Hello, Perl/Tk World!!');
        $o_label_0->pack();
        
        my $o_button_0 = $o_wm->Button(-text=>'Quit', -command=>\&quit);
        $o_button_0->pack();
      
        MainLoop();
    }
    
    # Buttonオブジェクトに関連付けた関数
    sub quit {
        exit(0);
    }

  • 次は実行です。実行方法は通常のPerlスクリプトと同じです。コマンドプロンプトからファイル名を指定する、又はエクスプローラ上でファイルをダブルクリックして下さい。下記のようなWindowが出ればOKです。

  • 確認後はQuitボタンで終了して下さい。

Tkで日本語を扱う(Perlの日本語処理一般)
  • 次はラベルに表示する文字列を "Hello, Perl/Tk World!!" から2byte文字混じりの日本語 "ようこそ、Perl/Tk ワールドへ!!" へ変えてみましょう(tk_test_01.pl)(*2)
    #!perl -w
    use Tk;
    use strict;
    
    {
        my $o_wm = MainWindow->new();
    
        my $o_label_0 = $o_wm->Label(-text=>'ようこそ、Perl/Tk ワールドへ!!');
        $o_label_0->pack();
        ...(略)...

  • 実行すると、下記のような文字化けした残念な結果になると思います。

  • 日本語を正しく表示するには、とりあえず、utf8プラグマを有効にし、スクリプトファイルの文字コードをUTF-8にして保存して下さい(tk_test_02.pl)。表示が正しくなるはずです。
    #!perl -w
    use Tk;
    use strict;
    use utf8;
    ...(略)...
     

  • Perl一般の話ですが、CPANモジュールを絡めて日本語等のマルチバイト文字を扱うには、スクリプトの文字コードはUTF-8とし、文字列リテラルにutf8プラグマを適用します。スクリプト外部とやり取りする文字列にはEndoceモジュールencode及びdecode関数を使用します。

  • Windows日本語環境では、スクリプト外側の文字コードはCP932(Shift_JIS)(*3)なので下記が使用例となります。
    #!perl -w
    use utf8;
    use Encode qw(decode encode);
    use strict;
    
    {
        # use utf8; により文字列リテラルは内部文字列(flagged utf8)として扱われる
          my $str0_int = "これは内部定義の文字列リテラル";
        
        # CP932のSTDINから入れた文字列はEncode::decode関数で内部文字列に変換
          my $str1_from_ext = decode('cp932', $ARGV[0]);
        
        # STDOUT出力時は、内部文字列をEncode::encode関数でCP932に変換
          my $str0_to_ext = encode('cp932', $str0_int);
          my $str1_to_ext = encode('cp932', $str1_from_ext);
        
        print '(1):internal:',$str0_to_ext,"\n";
        print '(2):argument:',$str1_to_ext,"\n";
    }
    > encode_test.pl 日本語のコマンドライン引数 (1):internal:これは内部定義の文字列リテラル (2):argument:日本語のコマンドライン引数

実行時にコマンドプロンプトが出てしまう
  • 先程作成したサンプルコード(tk_test_00.pl)ですが、エクスプローラからスクリプトファイルをダブルクリックして実行すると、コマンドプロンプトが出てしまうことに気付かれたでしょうか。

  • この対策ですが下記の方法があります。

  • (1)wperl.exeを使用する(拡張子を変更してwperl.exeに関連付ける)
    • wperl.exeですが、これはGUIプログラムの実行を想定したPerlです。WindowsでPerlをインストールした環境では、perl.exeと同じフォルダにあるでしょう。whereコマンドで確認してみて下さい。
        > where wperl
        C:\xx..xx\perl\bin\wperl.exe

    • 次はGUI系Perlスクリプトの拡張子を".plw"等に変更し、この拡張子をwperl.exeに関連付けます。ただ「誰かに渡す実行スクリプト」なのに「関連付け設定をして下さい」とは言いにくい...。

  • (2)ショートカットを作って"実行時の大きさ(R):"を設定する
    • スクリプトのショートカットを作成し、プロパティからショートカットのタブを選んで下さい。タブ内の"実行時の大きさ(R):"にて最小化を選択します。


      ※クリックで拡大

    • コマンドプロンプトだけが最小化され、GUI Windowはデスクトップに残る形で実行されます。Perl実行環境のあるPCでは使いやすい手です。

  • (3)Par::Packerのppコマンドを使用してExecutable版を作成する
    • Executable版を作ってしまう方法です。これだとPerl実行環境を持たないPCでも動作するツールとなります。

    • Tk同様にPAR::Packerモジュールをインストールします。Strawberry Perl環境ではcpanコマンドを使用します。
       > cpan PAR::Packer
        ※これも15分程度インストールに時間かかります

    • インストール終了後、導入されたppコマンドでExecutableファイルを作成します。--gui オプションがポイントです。
       > pp --gui -o exe版ファイル名 スクリプトファイル名
       (例)> pp --gui -o tk_test_02.exe tk_test_02.pl

    • エラー無く終了すればExecutable版が作成されます。アイコンは「ラクダ決め打ち」なんすか...そうすか。

実行ファイルのアイコン変更
  • PAR::PackerモジュールのppコマンドでExecutableファイルを作ると、アイコンはラクダ決め打ちです。普段Perlに触れている人ならわかるでしょうが、一般の人から見ると意味不明なので「ラクダ...好きなんだね...」という微妙なリアクションをされるでしょう。

  • 実行ファイルのアイコンは「直感的に何のアプリかを示す」ものなので、実は結構大事です。このアイコンを変更する方法ですが、ppコマンドの--icoオプションは現在機能が削除されており使えません。ppのPODには書いてあるんですけどね...。

  • ネットで他の方法を探したところ、Win32::Exeモジュールでアイコンを入れ替えるというやり方がありました。ワンライナーで書かれていますが要は下記です。
    #!perl -w
    use Win32::Exe; # これは標準モジュール
    use strict;
    
    {
        my $exe_name = $ARGV[0]; # 第1引数に実行ファイル
        my $ico_name = $ARGV[1]; # 第2引数にアイコンファイル
        
        my $o_exe = Win32::Exe->new($exe_name);   # 実行ファイルオブジェクト作成
        $o_exe->set_single_group_icon($ico_name); # アイコンファイル指定
        $o_exe->write; # 実行ファイル上書き
    }

  • ここで適用するアイコンファイルですが、厳密に24bitカラーの32x32ピクセルサイズにしなれけばなりません。しかし32x32ピクセルのbmpファイル拡張子をicoに変更する方法で作成したicoファイルはエラーになります。アイコン編集ツール等できちんと作成する必要があります。私はアイコンウィザードで作成しました。

  • ツールで作成したicoファイル(beer.ico)を、上記スクリプト(replace_icon.plとします)に与えてアイコンを入れ替えます。

    > replace_icon.pl tk_test_02.exe beer.ico
      →アイコン変更後→

  • 尚、アイコン表示はキャッシュされているので、一度エクスプローラを閉じて再度同じフォルダをオープンしないと、アイコンの変更を確認できません(*4)。ご注意下さい。

次回からTkのwidgetを触ってみる
  • 今回は、PerlでTkを使用したプログラム環境及び、気になる点を予め調べて終わりました。次回からTkのwidgetを触りながら進めていきたいと思います。
Notes
  • 画面でコード表示縦伸びしないようにコメントを削除しています。
  • 「うっ、それはまずい」と思った方は、このセクションをスキップしてOKです。
  • CP932はShift_JISのスーパーセットです。またEnceode::decode/encodeの文字コード表記解釈はかなり柔軟です。
  • ちなみにこのアイコンだと「ビール...好きなんだね...」って言われますが「はいっ!!」と答えます。
Copyright(C) 2022 Altmo
本HPについて