< バックアップ付きコピー | ファイル名に使用できない文字を判断する >

September 15, 2005

入力可能なコンボボックスにツールチップを設定する

MFC で、入力可能なコンボボックス (スタイルに CBS_DROPDOWN が設定されているもの) に対して、ツールチップを設定します。サンプルは、上が入力不可 (ドロップダウンリスト)、下が入力可能 (ドロップダウン) のコンボボックスです。それぞれ、m_DropdownList と m_DropdownCombo にマッピングしてあります。

ダイアログ

以下が、OnInitDialog 内でのツールチップ作成部分

// OnInitDialog
    if (m_ToolTip.Create (this))
    {
        m_ToolTip.AddTool (&m_DropdownList, _T ("ドロップダウンリスト"));
        m_ToolTip.AddTool (&m_DropdownCombo, _T ("ドロップダウンコンボ"));
    }

で、PreTransrateMessage で以下のようにしてツールチップにマウスイベントを渡します。

// PreTranslateMessage
BOOL CDropdownTooltipDialog::PreTranslateMessage (MSG* pMsg)
{
    switch (pMsg->message)
    {
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MOUSEMOVE:
        m_ToolTip.RelayEvent (pMsg);
        break;
    default:
        break;
    }
    return CDialog::PreTranslateMessage (pMsg);
}

ダイアログを表示して、コンボボックスをマウスでポイントすると、ドロップダウンリストの方はツールチップを表示しますが、ドロップダウンの方は表示しません。しかしドロップダウンの上辺の端ぎりぎりくらいにポインタを持っていくと、上のように表示されます。これは、ドロップダウンの方は入力するためのエディットボックスが前面に作成されているためです。というわけで、今回のお題はこちら。

Spy++ で確認すると、ドロップダウンの子ウインドウに、Edit クラスのウインドウが見えます。こいつの HWND を EnumChildWindow で取得することにします。まず、ダイアログクラスにコールバック関数を定義します。また、コールバック関数内で Edit の HWND を受け取りたいので、HWND 型のメンバ変数も追加しておきます。

// CDropdownTooltipDialog ダイアログクラスの宣言

class CDropdownTooltipDialog : public CDialog
{
    DECLARE_DYNAMIC(CDropdownTooltipDialog)

public:
    CDropdownTooltipDialog (CWnd* pParent = NULL);
    virtual ~CDropdownTooltipDialog (void);

    enum { IDD = IDD_DROPDOWNTOOLTIP };

protected:
    CToolTipCtrl    m_ToolTip;
    CComboBox       m_DropdownCombo;
    CComboBox       m_DropdownList;

    // エディットボックスのウインドウハンドル
    HWND            m_hWndDropdownEdit;

    virtual void DoDataExchange (CDataExchange* pDX);    // DDX/DDV サポート
    virtual BOOL OnInitDialog (void);
    virtual BOOL PreTranslateMessage (MSG* pMsg);
    afx_msg void OnDestroy (void);
    
    // EnumChildWindows のコールバック関数を追加
    static BOOL CALLBACK EnumChildOfDropdown (HWND hWnd, LPARAM lParam);

    DECLARE_MESSAGE_MAP()
};
// コールバック関数の実装
BOOL CALLBACK CDropdownTooltipDialog::EnumChildOfDropdown (HWND hWnd, LPARAM lParam)
{
    // ウインドウクラス名を取得します
    TCHAR szClassName [MAX_PATH];
    ZeroMemory (szClassName, sizeof szClassName);
    if (GetClassName (hWnd, szClassName, MAX_PATH))
    {   // Edit なら、求める HWND です(多分)
        if (0 == _tcsicmp (_T ("Edit"), szClassName))
        {
            ((CDropdownTooltipDialog *)lParam)->m_hWndDropdownEdit = hWnd;
            return FALSE;   // 列挙を中断します
        }
    }
    return TRUE;
}

OnInitDialog で、Edit の HWND を取得します。

BOOL CDropdownTooltipDialog::OnInitDialog (void)
{
    CDialog::OnInitDialog();

    if (m_ToolTip.Create (this))
    {
        m_ToolTip.AddTool (&m_DropdownList, _T ("ドロップダウンリスト"));
        m_ToolTip.AddTool (&m_DropdownCombo, _T ("ドロップダウンコンボ"));
    }

    // 子ウインドウを列挙
    BOOL bRet = ::EnumChildWindows (m_DropdownCombo, (WNDENUMPROC) EnumChildOfDropdown, (LPARAM) this);

    return TRUE;
}

で、問題は PreTranslateMessage。ここではコメントにもあるように、マウスイベントを受け取った場合に、それがドロップダウンのエディットボックスなら、HWND をドロップダウンに摩り替えて、イベントをツールチップに処理させます。

BOOL CDropdownTooltipDialog::PreTranslateMessage (MSG* pMsg)
{
    switch (pMsg->message)
    {
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MOUSEMOVE:
        if (pMsg->hwnd == m_hWndDropdownEdit)
        {// ドロップダウンの Edit なら、ドロップダウンの HWND として RelayEvent します。
            MSG Msg;
            CopyMemory (&Msg, pMsg, sizeof (MSG));
            Msg.hwnd = (HWND) m_DropdownCombo;
            m_ToolTip.RelayEvent (&Msg);
            break;
        }
        m_ToolTip.RelayEvent (pMsg);
        break;
    default:
        break;
    }
    return CDialog::PreTranslateMessage (pMsg);
}

トラックバック

このエントリーにトラックバック:
http://frog.raindrop.jp/cgi-bin/mt/mt-tb.cgi/1068

コメント

コメントする

※ コメントスパム対策のため、コメント本文はおはよう、こんにちわ、こんばんわのいずれかより始めるようにしてください。

name:
email:

※ 必要ですが、表示しません。

url:
情報を保存する ?