こんにちは、高木です。
ここのところTcl/Tkのラッパークラスを作っています。前回はwidgetクラスを派生してlabelクラスを作りました。Tkには多数のウィジェットがありますが、派生クラスはほとんど同じコードの連続になります。こういうときには以前連載していたPHPによる前処理が便利です。
最初に前回作ったlabelクラスをもう一度確認しておきましょう。
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 |
namespace tk { class label : public widget { static constexpr char8_t type[] = u8"label"; public: label(const widget& parent, const tcl::obj& name, std::initializer_list<tcl::obj> options) : widget(type, parent, name, options) { } ~label() noexcept = default; label(const label&) = default; label(label&&) = default; label& operator=(const label&) = default; label& operator=(label&&) = default; private: virtual tcl::obj do_type() const { return type; } }; } |
ほかのウィジェット、たとえばbuttonのラッパークラスを作るにはどうすればいいかを考えてみます。どうやら「label」となっているところを「button」に単純に置き換えるだけでも問題なさそうです。
単純に置き換えるだけでいいなら、labelクラスのコードをPHPの文字列として保持しておいて、PHPのstr_replace関数で置換するだけでもよさそうです。ただ、それではあまりにも融通がききませんので、「label」にあたる部分を$typeという変数にして埋め込むことを考えましょう。
その方針で作ったPHPの関数が下記になります。
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 26 27 28 29 30 |
<?php function make_widget_class(string $type) : string { return <<<EOT class $type : public widget { static constexpr char8_t type[] = u8"$type"; public: $type(const widget& parent, const tcl::obj& name, std::initializer_list<tcl::obj> options) : widget(type, parent, name, options) { } ~$type() noexcept = default; $type(const $type&) = default; $type($type&&) = default; $type& operator=(const $type&) = default; $type& operator=($type&&) = default; private: virtual tcl::obj do_type() const { return type; } }; EOT; } ?> |
あとは、生成するウィジェットの種類の数だけmake_widget_class関数を呼び出してあげればOKです。今回はとりあえずlabelとbuttonだけにしますが、種類が増えても同じことです。
0 1 2 3 4 5 6 7 |
<?php foreach ([ 'label', 'button' ] as $type) { echo make_widget_class($type); } ?> |
これでウィジェットクラスを量産できるようになりました。もし、特別なメンバーを追加する必要が出てきた場合は、make_widget_class関数に引数を追加してコールバック関数を渡してあげれば対応できますね。
現状のwidgetクラスでは、オプションの指定をコンストラクタでしか行うことができません。次回はTcl/Tkのコマンドでいうconfigureとcgetに相当するメンバー関数を追加していくことにします。