カスタム コントロール

このセクションには、アプリケーション定義コントロールまたはカスタム コントロールに関する情報が含まれています。

次のトピックについて説明します。

オーナー描画コントロールの作成

ボタン、メニュー、静的テキスト コントロール、リスト ボックス、コンボ ボックスは、オーナー描画スタイル フラグを使用して作成できます。 コントロールにオーナー描画スタイルがある場合、システムは、ユーザーがボタンを選択したことを検出してボタンの所有者にイベントを通知するなどのタスクを実行することで、コントロールとのユーザーの対話を通常どおりに処理します。 ただし、コントロールはオーナー描画のため、コントロールの外観はコントロールの親ウィンドウが担当します。 親ウィンドウは、コントロールを描画する必要があるときは必ずメッセージを受信します。

ボタンと静的テキスト コントロールの場合、オーナー描画スタイルは、システムがコントロール全体を描画する方法に影響を与えます。 リスト ボックスとコンボ ボックスの場合、親ウィンドウがコントロール内に項目を描画し、コントロールが独自のアウトラインを描画します。 たとえば、アプリケーションは、リスト内の各項目の横に小さいビットマップが表示されるようリスト ボックスをカスタマイズできます。

次のコード例は、オーナー描画の静的テキスト コントロールを作成する方法を示しています。 Unicode が定義されているとします。

// g_myStatic is a global HWND variable.
g_myStatic = CreateWindowEx(0, L"STATIC", L"Some static text", 
            WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, 
            25, 125, 150, 20, hDlg, 0, 0, 0);

次の例では、前の例で作成されたコントロールを含むダイアログ ボックスのウィンドウ プロシージャから、既定のフォントを使用してテキストをカスタム色で表示することにより WM_DRAWITEM メッセージが処理されます。 WM_DRAWITEM を処理するときに、BeginPaintEndPaint を呼び出す必要はありません。

case WM_DRAWITEM:
{
    LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
    if (pDIS->hwndItem == g_myStatic)
    {
        SetTextColor(pDIS->hDC, RGB(100, 0, 100));
        WCHAR staticText[99];
        int len = SendMessage(myStatic, WM_GETTEXT, 
            ARRAYSIZE(staticText), (LPARAM)staticText);
        TextOut(pDIS->hDC, pDIS->rcItem.left, pDIS->rcItem.top, staticText, len);
    }
    return TRUE;
}

オーナー描画コントロールについて詳しくは、「オーナー描画リスト ボックスの作成」と「オーナー描画コンボ ボックス」をご覧ください。

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

カスタム コントロールを作成するもう 1 つの方法として、既存のコントロールをサブクラス化できます。 サブクラス プロシージャは、選択された動作に影響を与えるメッセージを処理することにより、コントロールの選択された動作を変更できます。 他のすべてのメッセージは、コントロールの元のウィンドウ プロシージャに渡されます。 たとえば、アプリケーションでは、コントロールをサブクラス化し、WM_PAINT メッセージを処理することにより、読み取り専用の単一行編集コントロールのテキストの横に小さなビットマップを表示できます。 詳しくは、ウィンドウ プロシージャコントロールのサブクラス化に関するページをご覧ください。

アプリケーション定義ウィンドウ クラスの実装

既存のコントロールに明示的に基づいていないコントロールを作成するには、アプリケーションでウィンドウ クラスを作成して登録する必要があります。 カスタム コントロールのアプリケーション定義ウィンドウ クラスを登録するプロセスは、通常のウィンドウのクラスを登録するプロセスと同じです。 カスタム コントロールを作成するには、CreateWindowEx 関数またはダイアログ ボックス テンプレートでウィンドウ クラスの名前を指定します。 各クラスには、一意の名前、対応するウィンドウ プロシージャ、その他の情報が必要です。

少なくとも、ウィンドウ プロシージャはコントロールを描画します。 ユーザーが情報を入力可能にするため、アプリケーションでコントロールが使用されている場合、ウィンドウ プロシージャはキーボードとマウスからの入力メッセージも処理し、通知メッセージを親ウィンドウに送信します。 さらに、コントロールがコントロール メッセージをサポートしている場合、ウィンドウ プロシージャは、親ウィンドウまたは他のウィンドウによって送信されたメッセージを処理します。 たとえば、コントロールは、多くの場合、ダイアログ ボックスによって送信された WM_GETDLGCODE メッセージを処理して、キーボード入力を特定の方法で処理するようダイアログ ボックスに指示します。

アプリケーション定義コントロールのウィンドウ プロシージャは、メッセージがコントロールの操作に影響を与える場合、次の表の定義済みコントロール メッセージを処理する必要があります。

メッセージ 推奨
WM_GETDLGCODE コントロールが ENTER、ESC、TAB、または方向キーを使用するかどうかを処理します。 IsDialogMessage 関数は、このメッセージをダイアログ ボックス内のコントロールに送信して、キーを処理するかコントロールに渡すかを決定します。
WM_GETFONT WM_SETFONT メッセージも処理される場合に処理します。
WM_GETTEXT コントロール テキストが CreateWindowEx 関数によって指定されたタイトルと同じでない場合に処理します。
WM_GETTEXTLENGTH コントロール テキストが CreateWindowEx 関数によって指定されたタイトルと同じでない場合に処理します。
WM_KILLFOCUS コントロールにキャレット、フォーカスの四角形、または入力フォーカスがあることを示す別の項目が表示される場合に処理します。
WM_SETFOCUS コントロールにキャレット、フォーカスの四角形、または入力フォーカスがあることを示す別の項目が表示される場合に処理します。
WM_SETTEXT コントロール テキストが CreateWindowEx 関数によって指定されたタイトルと同じでない場合に処理します。
WM_SETFONT コントロールにテキストが表示される場合に処理します。 このメッセージは、DS_SETFONT スタイルのダイアログ ボックスを作成するときに送信されます。

 

アプリケーション定義コントロール メッセージは特定のコントロールに固有であり、SendMessage または SendDlgItemMessage 関数を使用してコントロールに明示的に送信する必要があります。 各メッセージの数値は一意でなければならず、他のウィンドウ メッセージの値と競合してはなりません。 アプリケーション定義メッセージ値が競合しないよう、アプリケーションは、WM_USER 値に一意の数値を追加することにより、各値を作成する必要があります。

コントロールからの通知の送信

ホスト アプリケーションがこれらのイベントに応答できるよう、イベントの通知を親ウィンドウに送信するには、カスタム コントロールが必要になることがあります。 たとえば、カスタム リスト ビューは、ユーザーが項目を選択したときに通知を送信し、項目がダブルクリックされたときに別の通知を送信する場合があります。

通知は、WM_COMMAND メッセージまたは WM_NOTIFY メッセージとして送信されます。 WM_NOTIFY メッセージには、WM_COMMAND メッセージよりも多くの情報が含まれています。

コントロール識別子は、メッセージを送信するコントロールを識別するためにアプリケーションが使用する一意の数値です。 アプリケーションは、コントロールの作成時にコントロールの識別子を設定します。 アプリケーションは、CreateWindowEx 関数の hMenu パラメーターまたは DLGITEMTEMPLATEEX 構造の id メンバーで識別子を指定します。

コントロール自体はコントロール識別子を設定しないため、コントロールは通知メッセージを送信する前に識別子を取得する必要があります。 コントロールは、独自のコントロール識別子を取得するために GetDlgCtrlID 関数を使用する必要があります。 コントロール識別子は、コントロールの作成時にメニュー ハンドルとして指定されますが、GetMenu 関数を使用して識別子を取得することはできません。 または、コントロールは、WM_CREATE メッセージの処理時に CREATESTRUCT 構造の hMenu メンバーから識別子を取得することができます。

次の例では、hwndControl がコントロール ウィンドウのハンドルになっており、CN_VALUECHANGED がカスタム通知定義になっています。コントロール固有の通知を送信する 2 つの方法を示しています。

 // Send as WM_COMMAND.
SendMessage(GetParent(hwndControl), 
    WM_COMMAND,
    MAKEWPARAM(GetDlgCtrlID(hwndControl), CN_VALUECHANGED),
    (LPARAM)hwndControl);

// Send as WM_NOTIFY.           
NMHDR nmh;
nmh.code = CN_VALUECHANGED;
nmh.idFrom = GetDlgCtrlID(hwndControl);
nmh.hwndFrom = hwndControl;
SendMessage(GetParent(hwndControl), 
    WM_NOTIFY, 
    (WPARAM)hwndControl, 
    (LPARAM)&nmh);

NMHDR 構造は、追加情報を含む、より大きなコントロール定義構造の一部になる可能性がある点に注意してください。 この例では、コントロールの古い値と新しい値がこの構造に含まれている可能性があります。 (このような拡張構造は、多くの標準通知で使用されます。たとえば、NMLISTVIEW 構造を使用する LVN_INSERTITEM をご覧ください)。

アクセシビリティ

すべての一般的なコントロールでは、Microsoft Active Accessibility (MSAA) がサポートされています。これにより、スクリーン リーダーなどのアクセシビリティ テクノロジ アプリケーションからのプログラムによるアクセスが可能になります。 MSAA を使用すると、新しいテクノロジである UI オートメーションがコントロールと対話することもできます。

カスタム コントロールは、(MSAA をサポートするため) IAccessible インターフェイス、UI オートメーション インターフェイス、またはその両方を実装する必要があります。 そうしないと、アクセシビリティ テクノロジ製品が、コントロール ウィンドウに関するごく限られた情報のみを取得可能になり、コントロールのプロパティにはアクセスできず、コントロール内のイベントをトリガーできなくなります。

コントロールをアクセシビリティ対応にする方法について詳しくは、「Windows Automation API」をご覧ください。

Conceptual

一般的なコントロール リファレンス

カスタム描画を使用してコントロールの外観をカスタマイズする

コントロール メッセージ

オーナー描画コントロールでビジュアル スタイルを使用する