テクニカル ノート 14:カスタム コントロールTN014: Custom Controls

このメモでは、カスタムコントロールと自己描画コントロールの MFC サポートについて説明します。This note describes the MFC Support for custom and self-drawing controls. また、動的サブクラス化についても説明し、CWnd HWNDオブジェクトと s の関係について説明します。It also describes dynamic subclassing, and describes the relationship between CWnd objects and HWNDs.

MFC サンプルアプリケーション CTRLTEST は、多くのカスタムコントロールの使用方法を示しています。The MFC sample application CTRLTEST illustrates how to use many custom controls. MFC の一般的なサンプルCTRLTESTとオンラインヘルプのソースコードを参照してください。See the source code for the MFC General sample CTRLTEST and online help.

オーナー描画コントロール/メニューOwner-Draw Controls/Menus

Windows では、Windows メッセージを使用したオーナー描画コントロールとメニューがサポートされています。Windows provides support for owner-draw controls and menus by using Windows messages. コントロールまたはメニューの親ウィンドウは、これらのメッセージを受信し、応答として関数を呼び出します。The parent window of any control or menu receives these messages and calls functions in response. これらの関数をオーバーライドすると、オーナー描画コントロールまたはメニューの外観と動作をカスタマイズできます。You can override these functions to customize the visual appearance and behavior of your owner-draw control or menu.

MFC では、次の関数を使用したオーナー描画が直接サポートされています。MFC directly supports owner-draw with the following functions:

CWnd派生クラスでこれらの関数をオーバーライドすると、カスタムの描画動作を実装できます。You can override these functions in your CWnd derived class to implement custom draw behavior.

この方法は、再利用可能なコードにはつながりません。This approach does not lead to reusable code. 2つの異なるCWndクラスに2つの類似したコントロールがある場合は、カスタムコントロールの動作を2つの場所に実装する必要があります。If you have two similar controls in two different CWnd classes, you must implement the custom control behavior in two locations. MFC でサポートされている自己描画コントロールアーキテクチャは、この問題を解決します。The MFC-supported self-drawing control architecture solves this problem.

自己描画コントロールとメニューSelf-Draw Controls and Menus

MFC でCWndは、標準のオーナー描画メッセージ用に既定の実装 (およびCMenuクラス) が用意されています。MFC provides a default implementation (in the CWnd and CMenu classes) for the standard owner-draw messages. この既定の実装では、オーナー描画パラメーターをデコードし、オーナー描画メッセージをコントロールまたはメニューに委任します。This default implementation will decode the owner-draw parameters and delegate the owner-draw messages to the controls or menu. これは、描画コードが [オーナー] ウィンドウではなく、コントロールまたはメニューのクラスにあるため、自己描画と呼ばれます。This is called self-draw because the drawing code is in the class of the control or menu, not in the owner window.

自己描画コントロールを使用すると、オーナー描画のセマンティクスを使用してコントロールを表示する再利用可能なコントロールクラスを構築できます。By using self-draw controls you can build reusable control classes that use owner-draw semantics to display the control. コントロールを描画するためのコードは、その親ではなく、コントロールクラスに含まれています。The code for drawing the control is in the control class, not its parent. これは、カスタムコントロールプログラミングに対するオブジェクト指向のアプローチです。This is an object-oriented approach to custom control programming. 自己描画クラスに次の関数の一覧を追加します。Add the following list of functions to your self-draw classes:

  • 自己描画ボタンの場合:For self-draw buttons:

    CButton:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw this button
    
  • 自己描画メニューの場合:For self-draw menus:

    CMenu:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this menu
    CMenu:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this menu
    
  • 自己描画リストボックスの場合:For self-draw list boxes:

    CListBox:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this list box
    CListBox:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this list box
    
    CListBox:CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this list box if LBS_SORT
    CListBox:DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this list box
    
  • 自己描画コンボボックスの場合:For self-draw combo boxes:

    CComboBox:MeasureItem(LPMEASUREITEMSTRUCT);
    // insert code to measure the size of an item in this combo box
    CComboBox:DrawItem(LPDRAWITEMSTRUCT);
    // insert code to draw an item in this combo box
    
    CComboBox:CompareItem(LPCOMPAREITEMSTRUCT);
    // insert code to compare two items in this combo box if CBS_SORT
    CComboBox:DeleteItem(LPDELETEITEMSTRUCT);
    // insert code to delete an item from this combo box
    

オーナー描画構造 (DRAWITEMSTRUCTMEASUREITEMSTRUCTCOMPAREITEMSTRUCT、およびDELETEITEMSTRUCT) の詳細についCWnd::OnDrawItem CWnd::OnCompareItemては、 CWnd::OnMeasureItem「」、「」、「」、および「」のMFCドキュメントを参照してください。CWnd::OnDeleteItemそれぞれ。For details on the owner-draw structures (DRAWITEMSTRUCT, MEASUREITEMSTRUCT, COMPAREITEMSTRUCT, and DELETEITEMSTRUCT) see the MFC documentation for CWnd::OnDrawItem, CWnd::OnMeasureItem, CWnd::OnCompareItem, and CWnd::OnDeleteItem respectively.

自己描画コントロールとメニューの使用Using self-draw controls and menus

自己描画メニューの場合は、メソッドとOnMeasureItem OnDrawItemメソッドの両方をオーバーライドする必要があります。For self-draw menus, you must override both the OnMeasureItem and OnDrawItem methods.

自己描画リストボックスとコンボボックスの場合は、およびをOnMeasureItem OnDrawItemオーバーライドする必要があります。For self-draw list boxes and combo boxes, you must override OnMeasureItem and OnDrawItem. ダイアログテンプレートでは、コンボボックスのリストボックスまたは CBS_OWNERDRAWVARIABLE スタイルに LBS_OWNERDRAWVARIABLE スタイルを指定する必要があります。You must specify the LBS_OWNERDRAWVARIABLE style for list boxes or CBS_OWNERDRAWVARIABLE style for combo boxes in the dialog template. 固定項目の高さは、自己描画コントロールがリストボックスにアタッチされる前に決定されるため、OWNERDRAWFIXED スタイルは自己描画項目では機能しません。The OWNERDRAWFIXED style will not work with self-draw items because the fixed item height is determined before self-draw controls are attached to the list box. (この制限を克服するには、 CListBox:: SetItemHeightメソッドとCComboBox:: SetItemHeightメソッドを使用できます)。(You can use the methods CListBox::SetItemHeight and CComboBox::SetItemHeight to overcome this limitation.)

OWNERDRAWVARIABLE スタイルに切り替えると、システムが NOインテグレーション ALHEIGHT スタイルをコントロールに適用するように強制されます。Switching to an OWNERDRAWVARIABLE style will force the system to apply the NOINTEGRALHEIGHT style to the control. コントロールでは、可変サイズの項目を使用して整数の高さを計算できないので、既定のスタイルである型の既定のスタイルは無視され、コントロールは常に NOインテグレーション ALHEIGHT になります。Because the control cannot calculate an integral height with variable sized items, the default style of INTEGRALHEIGHT is ignored and the control is always NOINTEGRALHEIGHT. 項目の高さが固定されている場合は、項目サイズの整数乗数としてコントロールのサイズを指定することで、部分的な項目が描画されないようにすることができます。If your items are fixed height, you can prevent partial items from being drawn by specifying the control size to be an integer multiplier of the item size.

LBS_SORT または CBS_SORT スタイルを使用した自己描画のリストボックスとコンボボックスの場合はOnCompareItem 、メソッドをオーバーライドする必要があります。For self-drawing list boxes and combo boxes with the LBS_SORT or CBS_SORT style, you must override the OnCompareItem method.

自己描画のリストボックスやコンボボックスの場合OnDeleteItem 、通常はオーバーライドされません。For self-drawing list boxes and combo boxes, OnDeleteItem is not usually overridden. 特別な処理OnDeleteItemを実行する場合は、をオーバーライドできます。You can override OnDeleteItem if you want to perform any special processing. これが適用されるケースの1つは、追加のメモリまたはその他のリソースが各リストボックスまたはコンボボックス項目と共に格納されている場合です。One case where this would be applicable is when additional memory or other resources are stored with each list box or combo box item.

自己描画コントロールとメニューの例Examples of Self-Drawing Controls and Menus

MFC の一般的なサンプルCTRLTESTでは、自己描画メニューと自己描画リストボックスのサンプルが提供されています。The MFC General sample CTRLTEST provides samples of a self-draw menu and a self-draw list box.

自己描画ボタンの最も一般的な例は、ビットマップボタンです。The most typical example of a self-drawing button is a bitmap button. ビットマップボタンは、状態が異なる1つ、2つ、または3つのビットマップイメージを表示するボタンです。A bitmap button is a button that shows one, two, or three bitmap images for the different states. この例については、MFC クラスのCbitmapbuttonを使用します。An example of this is provided in the MFC class CBitmapButton.

動的なサブクラス化Dynamic Subclassing

場合によっては、既に存在するオブジェクトの機能を変更する必要があります。Occasionally you will want to change the functionality of an object that already exists. 前の例では、コントロールを作成する前にカスタマイズする必要がありました。The previous examples required you to customize the controls before they were created. 動的サブクラス化を使用すると、既に作成されているコントロールをカスタマイズできます。Dynamic subclassing enables you to customize a control that has already been created.

サブクラス化は、ウィンドウWndProcのをカスタマイズWndProcして、既定WndProcの機能を呼び出すための Windows 用語です。Subclassing is the Windows term for replacing the WndProc of a window with a customized WndProc and calling the old WndProc for default functionality.

これは、クラスの派生C++と混同しないようにしてください。This should not be confused with C++ class derivation. 明確にするためC++に、基本クラス派生クラスは、Windows オブジェクトモデルのスーパークラスとサブクラスに似ています。For clarification, the C++ terms base class and derived class are analogous to superclass and subclass in the Windows object model. C++MFC と Windows サブクラスを使用した派生はC++機能的には似ていますが、では動的サブクラス化がサポートされていません。C++ derivation with MFC and Windows subclassing are functionally similar, except C++ does not support dynamic subclassing.

クラスCWndは、 C++オブジェクト (からCWnd派生) とHWNDWindows ウィンドウオブジェクト (と呼ばれます) の間の接続を提供します。The CWnd class provides the connection between a C++ object (derived from CWnd) and a Windows window object (known as an HWND).

次の3つの一般的な関連する方法があります。There are three common ways these are related:

  • CWndHWND作成します。CWnd creates the HWND. 派生クラスの動作は、からCWnd派生したクラスを作成することによって変更できます。You can modify the behavior in a derived class by creating a class derived from CWnd. アプリケーションHWNDCWnd:: Createを呼び出すと、が作成されます。The HWND is created when your application calls CWnd::Create.

  • アプリケーションは、をCWnd既存HWNDのにアタッチします。The application attaches a CWnd to an existing HWND. 既存のウィンドウの動作は変更されません。The behavior of the existing window is not modified. これは委任のケースであり、 CWnd:: Attachを呼び出して、既存HWNDCWndオブジェクトに対するエイリアスのエイリアスを作成することによって可能になります。This is a case of delegation and is made possible by calling CWnd::Attach to alias an existing HWND to a CWnd object.

  • CWndは、既存HWNDのにアタッチされ、派生クラスで動作を変更できます。CWnd is attached to an existing HWND and you can modify the behavior in a derived class. これを動的サブクラス化と呼びます。これは、実行時に Windows オブジェクトの動作、つまりクラスを変更するためです。This is called dynamic subclassing because we are changing the behavior, and therefore the class, of a Windows object at run time.

Cwnd:: SubclassWindowメソッドとCwnd:: SubclassDlgItemメソッドを使用して、動的なサブクラス化を実現できます。You can achieve dynamic subclassing by using the methods CWnd::SubclassWindow andCWnd::SubclassDlgItem.

どちらのルーチンもCWnd 、オブジェクトを既存HWNDのにアタッチします。Both routines attach a CWnd object to an existing HWND. SubclassWindowHWND直接受け取ります。SubclassWindow takes the HWND directly. SubclassDlgItemは、コントロール ID と親ウィンドウを受け取るヘルパー関数です。SubclassDlgItem is a helper function that takes a control ID and the parent window. SubclassDlgItemは、ダイアログテンプレートC++から作成されたダイアログコントロールにオブジェクトをアタッチするように設計されています。SubclassDlgItem is designed for attaching C++ objects to dialog controls created from a dialog template.

SubclassWindow を使用する場合の例については、CWnd の例を参照してSubclassDlgItemください。See the CTRLTEST example for several examples of when to use SubclassWindow and SubclassDlgItem.

関連項目See also

番号順テクニカル ノートTechnical Notes by Number
カテゴリ別テクニカル ノートTechnical Notes by Category