Topic : Common Controls
Author : Unknown
Page : << Previous 6  Next >>
Go to page :


specify a range indicating which characters are to be selected. If we pass 0 to nStartChar and -1 to nEndChar, all the characters in the edit box will be selected. Then we use a loop to check if the text contained in the edit box is identical to any item string in the list box. In case there is no hit, we will add this string to the list box by calling function CComboBox::AddString(...). Finally, a TRUE value is returned before this function exits.

Using this method, we can also trap other keystrokes such as DELETE, ESC to the combo box. This will make the application easier to use.

10 Implementing Subclass for the Edit Box of a Combo Box

Under certain conditions we may want to put restrictions on the contents of the list items. For example, sometimes we may want the combo box to hold only numerical characters ('0'-'9'), and sometimes we may expect it to hold only alphabetical characters ('a'-'z', 'A'-'Z'). In these cases, we may want to customize the properties of the edit box so that only a special set of characters can be accepted. If we are creating an edit box resource in dialog template, this can be easily achieved by setting its customizable styles. But for the edit box of a combo box, we can not customize its styles before it is created, so the edit box contained in a combo box will have only the default styles.

To customize the behavior of the edit box in a combo box, we need to use "subclass" technique. We can design our own class to intercept and process the messages sent to the edit box. Sample 10\CCtl demonstrates how to customize the edit box that belongs to a combo box. It is based on sample 9\CCtl, with two combo boxes customized as follows: combo box IDC_COMBO_SIMPLE allows only numerical characters to be input into the edit box; combo box IDC_COMBO_DROPDOWN accepts only alphabetic characters.

Designing New Classes

Before implementing subclass, we need to design two classes that have the above-mentioned new properties. In the sample, MCNumEdit and MCCharEdit are added for this purpose. Both of them are derived from class CEdit. In Developer Studio, a new class can be easily added by using Class Wizard through following steps: 1) Execute command Insert | New Class to invoke the Class Wizard. 2) Input the class name, select the header file and implemantation file name. 3) Select base class name.

To customize the input attributes of an edit box, we need to handle WM_CHAR message, which is used to indicate that a character is being input into the control. This message handler can also be added through using Class Wizard after it is invoked as follows: 1) Click "Message Map" tab, select "MCNumEdit" or "MCCharEdit" class name in window "Class name". 3) Highlight "MCNumEdit" or "MCCharEdit" in window "Object IDs". 4) Locate and highlight "WM_CHAR" in window "Messages". 5) Click "Add function" button.

The following is one of the two functions generated by Class Wizard:

void MCNumEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

CEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);

}


This function has three parameters. The first parameter nChar indicates the value of the key, which provides us with the information of which key being pressed. The Second parameter indicates the repeat count, and the third parameter holds extra information about the keystrokes.

If we want the keystroke to be processed normally, we need to call the base class version of this function. If we do not call this function, the input will have no effect on the edit box. The following code fragment shows two message handlers implemented in the sample:

(Code omitted)

Class MCNumEdit accepts characters '0'-'9' and backspace key, class MCCharEdit accepts characters 'A'-'Z', 'a'-'z' and backspace key.

Implementing Subclass

To use the two classes, we need to include their header files and use them to declare two new variables in class CCCtlDlg:

......

#include "CharEdit.h"

#include "NumEdit.h"


......

class CCCtlDlg : public CDialog

{

......

protected:

......

MCCharEdit m_editChar;

MCNumEdit m_editNum;

......

};


In the dialog box's initialization stage, we need to implement subclass and change the default behavior of the edit boxes. Remember in the previous chapter, function CWnd::SubclassDlgItem(...) is used to implement subclass for an item contained in a dialog box. Although the edit box within a combo box is a indirect child window of the dialog box, it is not created from dialog template. So here we must call function CWnd::SubclassWindow(...) to implement subclass. The following is the format of this function:

BOOL CWnd::SubclassWindow(HWND hWnd);

Here, parameter hWnd is the handle of the window whose behavior is to be customized. From sample 9\CCtl, we know how to obtain the handle of the edit box that belongs to a combo box. The following is the procedure of implementing subclass for IDC_COMBO_DROPDOWN combo box:

(Code omitted)

With the above implementation, the combo box is able to filter out the characters we do not want.

11 Owner Draw List Box and Combo Box

Like menu, list box and combo box do not have to bear plain text interface all the time. Sometimes we can customize them to display images. In the previous samples, when implementing a list box or a combo box, we always select "No" for the "Owner draw" style. Actually, the "Owner draw" style can be set to other two selections: "Fixed" and "Variable". For a "fixed" type owner-draw list box or combo box, each item contained in the list box must have a same height. For a "variable" type of owner draw list box or combo box, this height can be variable. Like the menu, the owner-draw list box or combo box are drawn by their owner. The owner will receive message WM_MEASUREITEM and WM_DRAWITEM when the list box or the combo box needs to be updated. For "fixed" type owner draw list box or combo box, WM_MEASUREITEM is sent when it is first created and the returned size will be used for all items. For "variable" type owner-draw list box or combo box, this message is sent for each item separately. Message WM_DRAWITEM will be sent when the interface of list box or combo box needs to be updated.

Owner-Draw Styles

Sample 11\CCtl demonstrates owner-draw list box and combo box. It is a dialog based application generated by Application Wizard. There are only two common controls contained in the dialog box: a list box IDC_LIST and a combo box IDC_COMBO. The list box supports "Fixed" owner-draw style, and the combo box supports "Variable" owner-draw style. The "Sort" style is not applicable to an owner-draw list box or combo-box, because their items will not contain characters.

Preparing Bitmaps

Six bitmap resources are added to the application for list box and combo box drawing. Among them, IDB_BITMAP_SMILE_1, IDB_BITMAP_SMILE_2, IDB_BITMAP_SMILE_3 and IDB_BITMAP_SMILE_4 have the same dimension, they will be used for implementing owner-draw list box. Bitmaps IDB_BITMAP_BUTTON_SEL and IDB_BITMAP_BUTTON_UNSEL have a different size with the above four bitmaps, they will be used together with IDB_BITMAP_BIG_SMILE_1 and IDB_BITMAP_BIG_SMILE_2 to implement owner-draw combo box.

Identifying Item Types

The following macros are defined for different item types:

#define COMBO_BUTTON 0

#define COMBO_BIGSMILE 1

#define LIST_SMILE_1 0

#define LIST_SMILE_2 1

#define LIST_SMILE_3 2

#define LIST_SMILE_4 3


Each macro represents a different bitmap. We will use these macros to set item data for list box and combo box. Since the item data will be sent along with message WM_DRAWITEM, we can use it to identify item types. This is the same with owner-draw menu.

Two CComboBox type variables m_cbBmp and m_lbBmp are declared in class CCCtlDlg through using Class Wizard, they will be used to access the list box and the combo box. In function CCCtlDlg::OnInitDialog(), the list box and the combo box are initialized as follows:

(Code omitted)

Instead of adding a real string, we pass predefined integers to function CComboBox::AddString(...) and CListBox::AddString(...) For owner-draw list box and combo box, these integers will not be used as buffer addresses for obtaining strings. Instead, they will be sent along with message WM_MEASUREITEM to inform us the item type.

Handling Message WM_MEASUREITEM

The standard message handlers for WM_MEASUREITEM and WM_DRAWITEM are CWnd::OnMeasureItem(...) and CWnd::OnDrawItem(...) respectively, they can be added through using Class Wizard.

The following is the format of function CWnd::OnMeasureItem(...):

void CWnd::OnMeasureItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);

This function is called to retrieve the size of item. It has two parameters, the first parameter nIDCtl indicates the ID of control whose item's size is being retrieved. The second parameter is a pointer to a DRAWITEMSTRUCT object, and we will use its itemData member to identify the type of the item. Since the value of this member is set in the dialog's initialization stage by calling function CComboBox::AddString(...), it must be one of our predefined macros (LIST_SMILE_1, LIST_SMILE_2...). In the overridden function, we need to check the value of nIDCtl and lpDrawItemStruct->itemData, load the corresponding bitmap resource into a CBitmap type variable, call function CBitmap::GetBitmap(...) to retrieve the dimension of the bitmap, and use it to set both lpDrawItemStrut->itemWidth and lpDrawItemStrut->itemHeight:

(Code omitted)

Handling Message WM_DRAWITEM

The following is the format of function CWnd::OnDrawItem(...):

void CWnd::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);

It also has two parameters. Like CWnd::OnMeasureItem(...), the first parameter of this function is the control ID, and the second parameter is

Page : << Previous 6  Next >>