はじめに
Mind Version 9 (Mind9)の開発も大詰めに来ています。なんとか年内にリリースしたいと思っています。着手は2022年の8月だったので2年4カ月も経過してしまいました。Mindのプロジェクトとしては最長です。初版Mind(1985年)のときは、グラフィックライブラリや通信ライブラリなどすべて含めても8カ月ぐらいでしたので、それと比べるとかなり長いです(^^;
GUI機能の追加
Mind9の大きな機能追加としてGUIアプリケーション(ウィンドゥを開くアプリケーション)を作成できることが挙げられます。
GUIエンジンとして Mind7 でも使っていたTcl/Tkを再び採用しました。Mind7の時はTcl/Tk 8.3という版でしたが今回はTcl/Tk8.6になります(Tcl/Tkは最近9が出ているらしいのでそのうち切り替えたいと思います)。
以前のMind7ではGUIを使うためにかなりの部分でTcl/Tkレベルのスクリプトを書く必要がありましたが、その形態はいわば、プログラム言語の中に別のプログラム言語を抱えるようなもので、自分としてもいまひとつの感がありました。Mind9ではTcl/Tkスクリプトは完全に隠されており、MindだけでGUIアプリを記述できるようになりました。
最近は他のプログラム言語でもGUIエンジンとしてTcl/Tkを使うようになっているようです。Python のGUIライブラリ Tkinter が有名で、ほかにもRuby/Tkなどもあるようです。他言語では明らかにTcl/Tkのコマンドに1対1で対応する実装のようですが、Mind9ではプログラムを簡略化するため、より抽象的な表現で済むよう(Tcl/Tkのことをまったく知らなくて済むよう)介入をしています。ソースコードを見ただけではTcl/Tkが使われていると思えないぐらいです。
Mind9で書いた簡単なサンプルプログラムのソースと画面、その次にMind7で書いたものも併せてお見せします。
(Mind9)
メインとは
ボタン1は 変数
メインウィンドゥで ボタンのIDを取得し ボタン1に 入れ
「これを押すと終了します」を ボタン1に テキストを設定し
実行終りの 実行情報を ボタン1に イベント処理を登録し
ボタン1を 有効化して配置する。
(Mind7)(古いMindです。生のTcl/Tkコードを書く個所があります)
イベント分岐とは 本定義 (パラメータ・・、パラメータ数、イベント名 → ・)
文字列事例をとる
"exit"なら 実行終り
例外なら イベント引数を捨て
事例終り。
メインとは
「button .b1 -text {これを押すと終了します} -command {mindcmd exit}」を 評価し
「pack .b1」を 評価する。
一方でコンパイラはMind8のそれとあまり変わっておらず、GUI向けとしてコンパイラに機能追加したのは起動オプションの追加などごくわずかです。したがってGUI機能のすべてはライブラリ管轄となります。
ユーザ作成のアプリケーションを配布するときは Tcl/Tkのランタイムライブラリ(GUIエンジン)を同梱する必要がありますが、アプリケーションのフォルダ内に同梱できるため一般的なアプリケーションプログラムの配布とそれほど変わりません。アプリの配布を受け取った人はTcl/Tkを別途インストールする必要はなく、自己完結型のパッケージソフトとして扱えます。
MindとTcl/Tkとの連携はこんな感じです
以下はGUIライブラリを作ったことの自身の振り返りとして、MndのプログラムとGUIエンジンであるTcl/Tkモジュールとのインターフェースについてお話します。(実はMind7のときからこのような手法をとっていたので当時とあまり変わっていません)
Mind記述アプリ
→Mind記述のMindランタイム
→C記述のMindランタイム(カーネル)
→DLL呼び出し→Tcl/Tkモジュール
という手順でMindからTcl/Tkの呼び出しを行います。
イベントが発生したときは上記を逆にたどり、最終的にMind記述の処理単語が動いてイベント処理をおこなう形となります。
Tcl/TkはDLL形態のモジュールとして提供されていて、ユーザ作成のアプリからTcl/Tkを呼び出すインターフェースが備わっており、非常によくできた仕組みだと思っています。
したがって「言語のランタイムの配下にTcl/Tkを組み入れる」ことはそれほどの困難はありませんでした。
とはいえ、アプリケーションを主としてTcl/Tkを従とする組み方は書籍も含めて文献が非常に少なく、Mind7のときに一度やっているはずなのに試行錯誤が必要でした。
Tcl/Tkモジュールを多少カスタマイズしソースからコンパイルし直すこともやっています。
この記事を読まれている方は、MindにTcl/Tkを組み入れることなぞ特別なことで自分には関係ないと思われるかも知れませんが、実質的には C(C++でもほぼ同じ)で書いたアプリケーションにTcl/Tkを組み入れることに等しく、組み入れる方法は有用だと思いますので、いつかは記事にしてみたいと思っています。
IDのこと
先のMind9で書いた hellowin.src というソースですが、以下がポイントです。
ボタン1は 変数
メインウィンドゥで ボタンのIDを取得し ボタン1に 入れ
上記はTcl/Tkレベルで言えば以下のようなコードに対応します。
button .button1
Tcl/Tkではウィジェット(GUIのパーツのこと)を作成するにはボタンなら「button」というコマンドを発行します。その第1引数がウィジェット名であり、他のウィジェットと区別できれば任意の綴りでも良いというものです。上のコードでは .button という名前を指定しています。
しかしMindのプログラムとして見れば(何でもいいと言われても)ウィジェット名を考えるのは”余計な作業”てしかなく、Mind9のライブラリではウィジェット名は自動生成としています。その代わりに整数値の”ID”を使います。このIDで以降の操作を行います。
先に挙げた hellowin.src にあるように、ボタンに表示するテキストと、それを押したときのイベント処理の指定はボタン生成の行とは別の行として記述しています。Tcl/Tkではパラメータ類はすべて buttonコマンドの引数として一気に記述しますが、ここが生のTcl/TkとMindで違うところです。
hellowin.exe を走らせると最終的に以下のTcl/Tkコードが実行されます。
button .wbtn002 -text {これを押すと終了します} -command {mindcmd MC_801A}
pack .wbtn002
実はIDを使うという手法は Mind for Androidのとき初めて導入し(そのときはJavaのAPIとやり取りをするため)、かなり良い方法であることが分かったので Mind9 でも使いました。Androidのときの経験が役に立ったことになります。