コントロールのサブクラス化

しばらくブログはお休みモード.今,TreeView を持つアプリを書いているのですが,TreeView のアイテムの名前を変更しようとしたときに,Enter キーを押すと OK ボタンにフォーカスを奪われてしまい意図した動きにならない(「名前の変更」の終了ではなく,ダイアログ自体が終了しています)と言う問題が発生しました.

この問題をどうやって回避するのかなぁと Web を漁っていると,どうやら「コントロールのサブクラス化」と呼ばれる方法で回避するようです.

static WNDPROC DefaultTreeViewEditProc; // サブクラス化する前のデフォルトのウィンドウプロシージャ
static LRESULT CALLBACK TreeViewEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_GETDLGCODE:
        return DLGC_WANTALLKEYS; // Enter, Esc キーなどの処理を行った事を通知
    default:
        break;
    }
    return CallWindowProc(reinterpret_cast<WNDPROC>(DefaultTreeViewEditProc), hWnd, msg, wParam, lParam);
}

static LRESULT CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_NOTIFY:
    {
        LPNMHDR header = reinterpret_cast<LPNMHDR>(lp);
        if (header->code == TVN_BEGINLABELEDIT) {
            HWND edit = (HWND)SendMessage(tree_view_handle, GWLP_WNDPROC, TVM_GETEDITCONTROL, 0, 0);
            DefaultTreeViewEditProc = (WNDPROC)SetWindowLongPtr(edit, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&EditProc));
        }
        break;
    }
    default:
        break;
    }
    return FALSE;
}

この方法を知る前は,キーボードのメッセージをフックして無理やり処理するなどしていたのですが,サブクラス化する事でだいぶスマートに処理できるようになりました.

Related Pages