こんにちは、高木です。
前回までTclの基本的な部分について考えてきました。しかし、最終的にやりたいことはTkを使うことです。今回からいよいよTkを扱っていきます。
Tkを扱うといってもいきなり難しいことはできません。最初はウィンドウを1枚出すだけにしましょう。
以前作ったinterpreter::createメンバー関数では、引数にtrueを渡せば(あるいは省略すれば)内部でTk_Init関数を呼び出すようになっています。ここまでできれば、あとはイベント処理を適切に行ってあげればウィンドウを表示することができます。
Tkのイベント処理にはTk_MainLoop関数を使います。引数もありませんので、単にTk_MainLoop関数を呼び出すだけでOKです。
せっかくなのでTk_MainLoop関数が何をやっているのか調べてみましょう。以下が実際のTk_MainLoop関数のコードです。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* *---------------------------------------------------------------------- * * Tk_MainLoop -- * * Call Tcl_DoOneEvent over and over again in an infinite loop as long as * there exist any main windows. * * Results: * None. * * Side effects: * Arbitrary; depends on handlers for events. * *---------------------------------------------------------------------- */ void Tk_MainLoop(void) { while (Tk_GetNumMainWindows() > 0) { Tcl_DoOneEvent(0); } } |
これはTk 8.6.12のソースコードから引用したものですが、以前のバージョンからほとんど変わっていないと思います。
Tk_GetNumMainWindow関数というのは、文字通りメインウィンドウの個数を返します。では、メインウィンドウとは何かというと、インタープリターごとのルートになるウィンドウのことです。
Tclでは複数のインタープリターを作ることができますので、メインウィンドウも複数になることがあります。すべてのメインウィンドウが閉じればループから抜けることになります。
Tcl_DoOneEvent関数というのはTclのイベントをひとつだけ処理します。引数に0を渡した場合は、制限なくすべてのイベントを処理します。
Tcl_DoOneEvent関数はイベントが処理されるまでブロックすることはしません。ですので、このループの中にC++のコードを紛れ込ませれば、アイドル時に何らかの処理を行わせることができそうです。
ただ、アイドル時に処理を行わせるのであれば、それ専用の登録関数があります。Tcl_DoWhenIdle関数がそれです。ただ、C言語の関数なので、C++で使うにはちょっと不便かもしれませんね。
Tk_MainLoop関数は単に呼び出せばいいだけですし、必要に応じて自分でループを書いた方が便利なこともあるので、今のところはラップするのはやめておきましょう。
ここまで来れば、interpreter::evaluateメンバー関数に何らかのスクリプトを渡したあと、Tk_MainLoop関数を呼び出してウィンドウが表示できるようになるはずです。
次回はC++で実装したコマンドを登録する方法を考えてみることにします。