WideStudio Programming (3-4)
~イベントプロシージャの登録

というわけで、vectorにしておくと楽になる処理の例が、CTGRWindowPlacementDlg::WPDImpl::SetupEventProcedures()です。

void CTGRWindowPlacementDlg::WPDImpl::SetupEventProcedures()
{
    std::vector::const_iterator	it;
    for( it = _rad_mw_w.begin(); it != _rad_mw_w.end(); ++it ) {
        (*it)->setStatus(False);
        m_oi_map.MemorizeInstanceForTheObject((*it),this);
        (*it)->addProcedureV("ep_rad_value_ch","ep_rad_value_ch",ep_rad_value_ch,
                             WSEV_VALUE_CH);
    }
    for( it = _rad_mw_h.begin(); it != _rad_mw_h.end(); ++it ) {
    .....

WideStudio/MWTに対してラジオボタンの設定値が変化した時にイベントプロシージャ(この場合はep_rad_value_ch()関数)を呼び出してもらえるようにするには、名前を二つ(たぶん、インスタンス単位でユニークであれば充分、なのでイベントプロシージャ名と同じ文字列を設定しています)とイベントプロシージャとして呼び出して貰う関数のアドレスと、どのイベントが発生した時に呼び出してもらうかとを、各ボタンに登録します。上に出ているように、タンゴレンではWSCvlabel::addProcedureV()メンバ関数を使ってお手軽に登録しています。

addProcedureVは、マニュアルに載ってないですが、WSCbaseクラスで宣言されているpublic関数です。やってくれることはaddProcedureと同じですが、わざわざWSCprocedureクラスのインスタンスを作ってaddProcedureするのは面倒くさいし意味が分からないのでタンゴレンでは主にこちらを使っています。他にも幾つか関数があるようですが、どう見てもこれが一番素直です。

その上の行に、謎の処理があります。

m_oi_map.MemorizeInstanceForTheObject((*it),this);

これは何をしているかというと、イベントプロシージャはstatic関数にする必要があるため、呼び出された時点ではクラスのどのインスタンスに対して呼び出されているのかが分かりません。m_oi_mapは、呼び出された時に渡されるobject引数(WSCbase*、ここでは(*it)が表している当該のWSCvradioへのポインタになります)と、所属しているクラスのインスタンスへのポインタのペアを記憶させておくメカニズムです。単一画面(単一インスタンス)を前提とするならば外部変数にCTGRWindowPlacementDlgへのポインタを記憶させておいても良いのですが、この方が気持ちが良いのでこうしています。

m_oi_map はstaticメンバ変数なので、クラスのインスタンスが幾つあってもアプリケーション全体で一つだけ実体を持ちます。CTGRWindowPlacementDlg::WPDImplクラスの中で下記のように宣言されています。

    /** オブジェクトとインスタンスを結びつけるためのマップ変数を宣言。 */
    static al::gui::ObjectInstanceMap	m_oi_map;

al::gui::ObjectInstanceMapテンプレートクラスは(ak::guiネームスペースで)その名の通りstd::mapを使って、下記のように宣言されています(関連部分のみ抜粋)。

template
class ObjectInstanceMap {
    std::map	m_object_instance_map;
public:
    void MemorizeInstanceForTheObject(Tobject *object,Tinstance* instance) {
        typename std::map::value_type	value(object,instance);
        m_object_instance_map.insert(value);
    }
    Tinstance* RecallInstanceForTheObject(Tobject *object) {
        typename std::map::iterator it;
        if( (it = m_object_instance_map.find(object)) == m_object_instance_map.end() )
            return NULL;
        return it->second;
    }
    .....
};

ちなみに、この画面ではすべてのボタンに対して一個のイベントプロシージャで処理をまかなっています。

(続く)