オープンソースの軽量スクリプト言語を使って 本格的なアプリケーションを開発できることを疑う人は, 今日あまりいないと思います。 しかし,過去を振り返れば,1990 年代初頭に現れた J. K. Ousterhout 氏の Tcl/Tk*8 が初めて人々の意識をその方向へと変革したといってよいでしょう。
配布されている Tcl/Tk のソースを手元の Unix ワークステーションでコンパイルし,インストールすれば, わずかなスクリプトを書くだけで,当時 Unix 界で主流だった Motif と見間違えるばかりの立派な外観を備えた GUI アプリケーションを作成できたのです。 大規模化に対する Tcl/Tk のプログラミング言語としての貧弱さが災いし, やがて流行は下火になりましたが, それが与えた衝撃と影響は歴史に留められるべきものです。
特筆すべきもう一つの特徴として, Tcl/Tk のインタープリタは,自分自身を ライブラリとして C 言語のプログラムに簡単に組み込めるようになっていました。 他の言語処理系のほとんどが効率良いメモリ管理のために精巧で複雑な組込み用 API を用意していたのに対し, Tcl/Tk のそれは効率を犠牲にして極端に簡素化した, 融通のきく仕様になっていました。 誰でも簡単に自分のプログラムに Tcl/Tk インタープリタを組み込めるようにしていたわけです。
そもそも Tcl は Tool Command Language, Tk は ToolKit を意味しています。 Tcl は, ツールとしてのコマンド解釈・実行機能, いわゆるスクリプティング機能を 各プログラムに付与するための言語, Tk は,Tcl から利用できる GUI ツールキットというわけです。 GUI 機能が不要,あるいは他にある場合は, Tcl だけを利用することも可能でした。
Tcl によるプログラム例: tclsh は Tcl を組込みでなく単体で使うためのシェル。 実行すると,標準出力に hello, world と書く。
#!/usr/bin/tclsh puts "hello, world"
Tcl/Tk による GUI プログラム例 : wish は Tcl/Tk を組込みでなく単体で使うためのシェル。
#!/usr/bin/wish label .la -text "hello, world" pack .la
Unix 上での上記の実行例:
hello, world と書かれたラベル (label) が表示される。
この二つの特徴の帰結として, いろいろなプログラミング言語で GUI 構築能力を手軽に実現するために Tcl/Tk 組込みライブラリの インタフェースを用意することが流行しました。*9 それらのインタフェースの中で最も初期からあり, 最も一般的に使われたものの一つが, Python の Tk インタフェース,すなわち Tkinter でした。 これは,簡単にいえば,Tk のウィジェット (widget,いわゆる画面部品)*10 を Python のクラスのインスタンスとして扱えるようにするモジュールです。 (その内部では,インスタンス構築やメソッド呼出しなど, Python の言葉で与えられた GUI 処理を, Tk を呼び出す Tcl 言語に変換し, 組込み用 API 経由で組込み Tcl/Tk インタープリタに伝達し, その結果ないしコールバック呼出しを Python の言葉に逆変換する, ということをするわけです)
当時,Tcl/Tk はその人気により,もともとの X11/Unix だけでなく, Windows や Mac OS にも移植されました。 そのため自然と Tkinter は,Python で各種プラットフォームへの移植性がある GUI を構築するための手段となりました。 Tkinter は当初は Python 本体のソースとは別に配布されていましたが, やがて標準ライブラリに取り込まれました。
Tcl/Tk は先走りという形容が適切なほど早期から Unicode を採り入れていました。 そのため,実のところ,日本語を扱うとき, 少し前までの Python とは (その意味では Unix 等とも) 必ずしもしっくりいっていなかった点がありました。 はっきりいえば, 当時の実情に比べ明らかにオーバースペックかつオーバーテクノロジーでした。 他の事情もありますが, Unicode を採り入れたバージョン 8.1 のリリース後も, 長期にわたり日本語 EUC パッチのあたったバージョン 8.0 ないしそれ以前の版が日本の Unix 界で使われ続けたのは事実です。 (たとえば Plamo Linux 4.03 は, 今でも日本語 EUC パッチを適用した 8.0 版と, 国際化対応の 8.3 版の両方の Tcl/Tk を同梱しています)
しかし,現在の Python は十分な Unicode サポートを備えているため, Tcl/Tk と車の両輪で移植性の高いプログラムを実現できます。
現在,Cygwin の tcltk パッケージとして用意されている Tcl/Tk は
バージョン 8.4.1 です。
Cygwin で python パッケージを導入しとき,依存関係により,
tcltk パッケージも導入されているはずです。
下記を行えば,Tcl/Tk 単体による包括的なデモの実行とソースの閲覧が
できます。Tcl/Tk でできる GUI の限界は概ねこれで把握できます。
是非実行してみてください。
01:~$ /usr/share/tk8.4/demos/widget &
デモの実行例を右図に示します。
Cygwin の bash のコマンドプロンプトのほかに二つのウィンドウが表示されています。
Tcl/Tk の作成したウィンドウです。
Cygwin の Tcl/Tk は X11 に依存しません。ネイティブに描画します。
最も手前のウィンドウでは, Windows の日本語 IME を使って Tk のウィジェットに日本語文を書き込み, 日本語の単語を検索しています。
実際のところ,Tcl/Tk は,
それ単体で GUI アプリケーションを構築する手段にできます。
ただし,
大規模プログラミングに対するサポートが十分とはいえないため,
気をつけないと容易に見通しの悪いコードに成長してしまうきらいがあります。
これを克服する一つの方法は
[incr Tcl]
のようなオブジェクト指向拡張を利用することですが,
本稿では Python から Tkinter 経由で Tcl/Tk を利用する方法を考えます。
ちなみに [incr Tcl] とは変数 Tcl を 1 だけ増やす Tcl 言語の式です。
C に対する C++ と同じです。
モジュール Tkinter とそれに付随する補助モジュール群は, /usr/lib/python2.4/lib-tk/ にあります。 Tcl/Tk のライブラリと実際に C 言語 API で対話するのは, Tkinter 内部から利用される C モジュール /usr/lib/python2.4/lib-dynload/_tkinter.dll です。 (したがって,_tkinter.dll を §14.2 のように cygchek コマンドにかけると, C:\cygwin\bin\ の tcl84.dll と tk84.dll に依存していると表示されます)
実際にプログラムから Tkinter を使うときは, 次のように from 付き import 文を使うのが普通です。
from Tkinter import *
この文は Tkinter モジュールの名前空間の内容を,現在のモジュールの名前空間に
取り入れます。いちいち Tkinter.Button などと書かずに単に Button とだけ
書けるようになります。
(§15.1 の
式 math.sin(0.5) は,実は,from math import * を使えば
単に sin(0.5) と書けたわけです。
なお,アンダースコアで始まる名前は非公開扱いされますから,
from ... import では取り入れられません)
前述の Tcl/Tk による GUI プログラム例 を Tkinter で実行してみます。この程度の長さならば, 気軽に Python の対話セッションで試してもよいでしょう。 最後の root.mainloop() の行を入力すると下図のウィンドウが 現れるはずです。
>>> from Tkinter import * >>> root = Tk() >>> la = Label(root, text="hello, world") >>> la.pack() >>> root.mainloop()
ウィンドウの × マークをクリックして閉じると, Python の対話セッションにプロンプトが戻ってきます。 ここでポイントを述べると
Tkinter を理解する一番よい方法は,Tcl/Tk を少しかじってから, モジュールのソース Tkinter.py を眺めつつ, Tkinter の単純なサンプルコードを読んで4,5個動かしてみることです。 Tkinter は,Python からの関数呼出しの引数を一定の規則で変換して Tcl/Tk に引き渡しているだけですから, 概要さえ理解すれば細部については Tcl/Tk のマニュアルを参照すれば十分です。
過去の大流行のなごりとして日本語による書籍も含め Tcl/Tk の文献は豊富ですから, 資料に困ることはないと思います。 一見すると,Tcl 言語も学習しなければならなそうで大変に思えますが, Tcl はシンプルな言語ですから,Tk のマニュアルを引けるようになる程度ならば, 一日もかければ十分マスターできます。
言語としての Tcl については, http://www.interq.or.jp/japan/s-imai/tcltk/ の http://www.interq.or.jp/japan/s-imai/tcltk/primer.html が Web 上の日本語による入門資料として手ごろです。
Tkinter については,英語ですが, http://wiki.python.org/moin/TkInter がよくまとまっています。 日本語による Tkinter の資料については,残念ながら, しっくりいっていなかった時代の 煩雑さをまだ引きずっているところが多い点に注意してください。
http://www.python.org/ などから Python のソースコードをダウンロードすれば,その Demo/tkinter/ の下に包括的なサンプル・プログラムが用意されています。 たいていの用途については,その真似で作れば十分です。
ここでは新しい Python の特徴である Unicode を利用した例を説明します。 Python には §15.2 の措置が 施してあるものとします。
前節の例の文字列定数を Unicode 文字列に変更した次の例を試してください。
>>> from Tkinter import * >>> root = Tk() >>> la = Label(root, text=u"あかさたな") >>> la.pack() >>> root.mainloop()
引き続き, 文字列の前の u を取り除いた次の例も試してください。 行編集機能を使えば簡単です。
>>> root = Tk() >>> la = Label(root, text="あかさたな") >>> la.pack() >>> root.mainloop()
前者は日本語が表示され,後者は文字化けします。 これから分かるように,Unicode を使えば日本語を出せます。 ちなみにテキスト・エントリなどで日本語を入力した場合, 結果は Unicode 文字列で得られます。
少し補足すると
GUI の世界ではさまざまな文化に由来するさまざまな Unicode 文字が入力される 可能性がありますが, ASCII 互換の通常の文字列でそれに堪えられるのは utf-8 だけです。 旧版 Python のように Unicode 文字列を十分に扱えなかったときは, この事実はデフォルトエンコーディングの選択に矛盾をもたらしました。 一方,Unicode 文字列を自然に扱えるとき,これはとりたてて問題になりません。 ごく粗い言い方をすれば, 人間可読とは限らないバイト列のために通常文字列を使い, 文字を表すために Unicode 文字列を使う,と割り切ればよいわけです。
これは bash からサンプルプログラムを Meadow で編集して, python で実行している例です。 図の右中にあって,「〜サンプルプログラム〜」というタイトルで, 「空とぶ」と入力している途中になっているのが, サンプルプログラムのウインドウです。
既にお気づきかと存じますが, §6 と §8 で紹介した Meadow の設定は, Python 編集モードを組み込んでいますから, そのまますぐに Python プログラムの作成に利用できます。
サンプルプログラムのファイルはここにあります。 ここでこれが (Cygwin では異端の) euc-jp で書かれていることに注目してください。 Unicode 文字列を使っていますから,こうしても動作に問題ありません。 比較のため shift_jis に書き換えたファイルを ここに置いておきます。 実際に両方動かして,どちらも動作に変わりがないことを確認してください。 (この二つは改行コードも違っていることに注目してください。 今の Python は改行コードについても柔軟に受理するようになっています)
前述のように Tcl/Tk は Unicode に対応していますから, IME パッドの文字一覧から, 周易の八卦やチェスの駒のような変わった Unicode 文字を入力しても動作します。 (ちなみにアラビア文字を入れた場合,Enter で確定させると, きちんと右から左に並ぶように表示されます。ただし,原因はよく分かりませんが, あまりエキゾティックな文字を入れると動作が不安定になることがあるようです)
文字コード以外の論点としては, 一部,前節の繰り返しになりますが, 次の事項に注意してください。
Tkinter を利用した代表的なアプリケーションとして,
本格的なソリティア・プログラム PySol
を挙げることができます。
これを動かすためだけに Python をインストールする人が現れても不思議ではない
ほどの完成度の高さがあります。
(右図)*12
PySol は GNU GPL の下でリリースされており, そのライセンスにしたがって Debian GNU/Linux の deb パッケージ など,ネットワーク上のあちこちで配布されています。
ここでは自分のお気に入りのバージョンである PySol 4.81 を Cygwin 上の Python で動かしてみます。
(1) GNU GPL の下で配布されている pysol-4.81.tar.bz2 と pysol-4.81-src.tar.bz2 を入手します。 (便宜のためここに pysol-4.81.tar.bz2 と pysol-4.81-src.tar.bz2 を用意しました)
(2)
同一ディレクトリに展開します。
ここでは /usr/local/lib に展開してみます。
01:~$ cd /usr/local/lib 01:/usr/local/lib$ tar xjf ~/pysol-4.81.tar.bz2 01:/usr/local/lib$ tar xjf ~/pysol-4.81-src.tar.bz2
(3) Python の各バージョンごとのバイトコンパイル済みバイナリファイルと, そのランチャである pysol スクリプトがあります。 しかし,なにしろ昔のファイルですから, 今のバージョンには適合しません。あるだけ無駄ですから消します。
01:/usr/local/lib$ cd pysol-4.81 01:/usr/local/lib/pysol-4.81$ rm pysol data/*.pyc
(4) 独自のモジュール pysolsoundserver を import している箇所が一箇所あります。 サウンドに必要なモジュールです。 本来なら気合を入れてこれも移植するべきでしょうが, ここではとりあえず動かすことを優先して,ダミーの代入文に書き換えます。 (モジュールもオブジェクトであり, import 文は変数にモジュールを代入する代入文であることを思い出してください)
01:/usr/local/lib/pysol-4.81$ cd src 01:/usr/local/lib/pysol-4.81/src$ \ > sed -i~ -e 's/import pysolsoundserver/pysolsoundserver = None # &/' \ > pysolaudio.py
(5) 書換えが成功しているか確認します。
01:/usr/local/lib/pysol-4.81/src$ diff pysolaudio.py~ pysolaudio.py 40c40 < import pysolsoundserver --- > pysolsoundserver = None # import pysolsoundserver
(6) ソースから起動するシェルスクリプトを新しく用意します。 サウンドに必要なモジュールを省いているので, スクリプト内のコマンド行に --nosound オプションを含めます。
01:~$ cd /usr/local/bin 01:/usr/local/bin$ echo '#!/bin/sh - > exec /bin/python /usr/local/lib/pysol-4.81/src/pysol.py --nosound' > pysol 01:/usr/local/bin$ chmod a+x pysol
(7) 起動してみます。
01:~$ pysol &
古いプログラムですので,Deprecation Warning が出ますが, 非 ASCII 文字がエンコーディング宣言 なしに使われたというだけですので, さしあたり無視してかまいません。 2回目の起動からは警告は出なくなります。 言語の字句解析に関係する警告のため, いったん起動されてバイトコンパイル済みファイル(*.pyc) が自動生成されると, 2回目からは解析されないからです。
ここでは今の Cygwin と Python を使って,
Python の傑作アプリケーションのひとつである3年前の PySol を動作させました。
*13
もちろん,これは完璧な移植ではありません。とりあえずのまにあわせです。
サウンドも含めた完全移植をめざす有志の方が現れることを期待しつつ,
この節を終わります。
*8
おおよその発音は「ティックル・ティーケー」です。
文献によれば,
Tcl は 1990年1月25日(木)に Washington, D. C. の USENIX 冬の大会で,
Tk は 1991年1月24日(木)に Texas 州 Dallas の同じく USENIX 冬の大会で
発表されたもようです。
Ousterhout, J. "Tcl: An Enbeddable Command Language",
Proc. USENIX Winter Conference, January 1990, pp. 133-146.
Ousterhout, J. "An X11 Toolkit Based on the Tcl Language",
Proc. USENIX Winter Conference, January 1991, pp. 105-115.
*9 この流行はほそぼそと,しかし脈々と最近まで続いています。たとえば, マイクロソフトがソースを配布している SSCLI (Shared Source Common Language Infrastructure) には, Windows, FreeBSD, Mac OS X 上で .NET から Tcl/Tk を利用して GUI を作るサンプル (PIGUI) が含まれています。
*10 widget は window と gadget (小道具,部品) を合成したかばん語です。
*11
S. M. Gava 氏による易占プログラム
pyChing
がその実例です。
Unicode 機能が全くない Python 1.5.1 用に書かれ,
2000 年 2 月 14 日にリリースされた 0.9.3 版を今動かしてみても (右図),
日本語の入力や保存に問題はありません。
易占結果をセーブするとき,日本語は Unicode のエスケープ列として保存され,
あとから問題なくロードできます。
テキスト・ファイル出力では,§15.2 の
設定によって Shift JIS で出力されます。
(GNU GPL 下のものですから,便宜のため,
ここ にも置いておきます。
あえて不具合を挙げれば,時代遅れの標準モジュール whrandom
を使っているため,起動時に Deprecation Warning が出ることぐらいです)
*12 他のスクリーンショットと見かけが違っていますが,これはもともと, 1年半前にディスククラッシュで消えた幻の第6章のために Windows 2000 で作成したものです。
*13
PySol を GNU GPL で公開して下さった
M. F. X. J. Oberhumer 氏に感謝します。
ただ,残念なことに,
PySol の 本家サイトでは,
GPL 採用に対する後悔と,
きたるべき新バージョン PySol5 からの,
より制約されたライセンスへの移行の可能性を表明しています
(出所を偽装した海賊版は,
著作権に立脚している GPL でも同様にライセンス違反です。
ライセンス違反を気にかけない悪党による
そのような海賊版を GPL 以上に阻止したいとすれば,
考えられる可能性はただ一つ,
ここで考慮されているライセンスはソース非公開のものであると予想されます)。
長らく動きのなかったプロジェクトが
再び活動を示し始めたことはうれしいことですが…。
(良い意味でも悪い意味でも,GPL は自由を守ることを最優先にしたライセンスです。
いったん GPL で配布されたバージョンについては,
作者はあとから撤回不可能です。人々はそのままそれを GPL の下で利用できますし,
独自に改訂版を作ることも可能です。
自由なソフトウェアを人々が安心して使うためには,いずれも欠かせないことです。
しかしながら,
このような理屈を持ち出すことは,あまり幸せな状況とはいえないかもしれません。
願わくば GPL でのリリース継続を望みたいところです)