こんにちは高木です。今回は久々にTcl/Tkの話をしようと思います。
いろいろなソフトウェアを開発していると、最終的な製品には必要なくても、開発段階ではデバッグ等にGUIが必要、またはあれば便利という状況が多々あります。私の場合、WindowsもLinuxも使います。最近は機会が減りましたがmacOSを使うこともたまにはあります。なので、できればどの環境でもほぼ同じように使えるGUIツールキットがあれば助かります。そんなときに重宝するのがTcl/Tkです(macOSだと日本語入力ができない問題がああった気がしますが……)。
Tcl/Tkは古くさい印象があるかもしれません。あるいは、まったく聞いたことすらない方さえいることでしょう。しかし、現在でもTcl/Tkは開発が継続中であり、新機能も追加されています。ライセンス的にかなり緩いのも魅力です。
モダンな開発環境大好きな方々が手放せないGitでも、標準のGUIにはTcl/Tkが使われています。最近流行のPythonも標準のGUIツールキットはTkinterです。TkinterはTkをPythonに移植したものです。このように、現在でもさまざまな場所で、さまざまな形で、Tcl/Tkは使われています。
主にスクリプト言語として知られるTcl/Tkですが、元々はアプリケーションに組み込みコマンド言語の機能を提供するためのライブラリでした。なので、既存のプログラムに後からくっつけて、GUIをはじめとした機能を追加するにはもってこいなのです。
Tcl/TkのGUIツールキットであるTkは、先ほど紹介したPythonのほか、Perl、Ruby、PHPなどさまざまな言語にバインディングされています。しかし、そもそもはCのライブラリであり、Cからであれば、最新のTcl/Tkを制限無く使うことができます。もちろんC++からでもです。
C++からTcl/Tkを使うための簡単なコード例を挙げてみることにします。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <tk.h> int main(int argc, char* argv[]) { Tcl_Interp* interp = Tcl_CreateInterp(); Tcl_FindExecutable(argv[0]); Tcl_Init(interp); Tk_Init(interp); char script[] = "pack [label .l -text {Hello, World!}]"; Tcl_Eval(interp, script); Tk_MainLoop(); Tcl_Finalize(); } |
このコードは、ウィンドウに「Hello, World!」と書いたラベルを貼るだけの簡単なものです。初期化と終了処理を除けば、わずか3行で書けてしまいます。Tcl以外のスクリプト言語からTkを使う場合でもそれほど大差はありません。
あと付けでGUI機能を追加するのであれば、GUI専用のスレッドを作ってそこでTcl/Tkを使うほうが便利です。せっかくなので、別スレッドでTcl/Tkを使う方法も挙げておきましょう。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <thread> #include <tk.h> int main(int argc, char* argv[]) { std::thread tkthread([argv]() { Tcl_Interp* interp = Tcl_CreateInterp(); Tcl_FindExecutable(argv[0]); Tcl_Init(interp); Tk_Init(interp); char script[] = "pack [label .l -text {Hello, World!}]"; Tcl_Eval(interp, script); Tk_MainLoop(); Tcl_Finalize(); }); tkthread.join(); } |
ほとんど変わりませんが、これで期待した結果は得られます。
実行環境となるハードウェアが完成していない状態でソフトウェアの開発を進めていかないといけない場合でも、Tcl/Tkでハードウェアのエミュレーションを行えば、かなりのところまで作り込みができます。
それ以外にもいろいと応用価値があると思います。どんな応用があるか、みなさんも考えてみてください。
今回の内容は別のブログに掲載していた記事を加筆修正したものです。今後もTcl/Tkについてはたびたび取り上げていくと思います。