分享
 
 
 

Common Control Fundamentals

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Common Control Fundamentals

MFC provides classes to wrap the common controls just as it provides classes to wrap the core control types implemented in User.exe. The following table shows the 20 types of common controls, the WNDCLASSes on which they're based, and the corresponding MFC classes. It also shows aliases for those WNDCLASSes defined in the header file Commctrl.h. Image lists and property sheets don't have WNDCLASSes because they're not controls in the strict sense of the word, but they're nearly always counted among the common controls because their code resides in Comctl32.dll. You'll sometimes see drag list boxes shown with the common controls. I didn't include them here because drag list boxes aren't stand-alone controls; they're conventional list boxes that are converted into "drag" list boxes by a function in Comctl32.dll. MFC provides a convenient implementation of drag list boxes in CDragListBox, so for more information, see the documentation for CDragListBox.

The Common Controls

Control Type

WNDCLASS

WNDCLASS Alias

MFC Class

Animation

"SysAnimate32"

ANIMATE_CLASS

CAnimateCtrl

ComboBoxEx*

"ComboBoxEx32"

WC_COMBOBOXEX

CComboBoxEx

Date-Time*

"SysDateTimePick32"

DATETIMEPICK_CLASS

CDateTimeCtrl

Header

"SysHeader32"

WC_HEADER

CHeaderCtrl

Hotkey

"msctls_hotkey32"

HOTKEY_CLASS

CHotKeyCtrl

Image list

N/A

N/A

CImageList

IP address**

"SysIPAddress32"

WC_IPADDRESS

CIPAddressCtrl

List view

"SysListView32"

WC_LISTVIEW

CListCtrl

Month calendar*

"SysMonthCal32"

MONTHCAL_CLASS

CMonthCalCtrl

Progress

"msctls_progress32"

PROGRESS_CLASS

CProgressCtrl

Property sheet

N/A

N/A

CPropertySheet

Rebar*

"ReBarWindow32"

REBARCLASSNAME

CReBarCtrl

Rich edit

"RichEdit20A" (ANSI) or "RichEdit20W" (Unicode)

RICHEDIT_CLASS

CRichEditCtrl

Slider

"msctls_trackbar32"

TRACKBAR_CLASS

CSliderCtrl

Spin button

"msctls_updown32"

UPDOWN_CLASS

CSpinButtonCtrl

Status bar

"msctls_statusbar32"

STATUSCLASSNAME

CStatusBarCtrl

Tab

"SysTabControl32"

WC_TABCONTROL

CTabCtrl

Toolbar

"ToolbarWindow32"

TOOLBARCLASSNAME

CToolBarCtrl

ToolTip

"tooltips_class32"

TOOLTIPS_CLASS

CToolTipCtrl

Tree view

"SysTreeView32"

WC_TREEVIEW

CTreeCtrl

* Requires Internet Explorer 3.0 or later.

** Requires Internet Explorer 4.0 or later.

As you can see from the table, some of the common controls are only supported on systems that have a particular version of Internet Explorer installed. That's because when you install Internet Explorer, the setup program silently upgrades Comctl32.dll, too. Many times in this chapter I'll say something like "This style is only supported on systems equipped with Internet Explorer 3.0 or later" or "This feature requires Internet Explorer 4.0." In truth, it's not Internet Explorer that's required but the version of Comctl32.dll that comes with that version of Internet Explorer. Because installing a more recent version of Internet Explorer is presently the only legal way to get the latest version of Comctl32.dll, Internet Explorer is a reasonable basis for documenting version dependencies.

Given the common controls' myriad dependencies on the version of Comctl32.dll that's installed and the fact that some systems don't have Internet Explorer installed at all, you might wonder how to determine at run time whether a given feature is supported provided that you know what version of Comctl32.dll it requires. Here's a simple routine that returns Comctl32.dll's major and minor version numbers. It returns 4.0 if the Comctl32.dll installed on the host system is one that predates Internet Explorer 3.0, and 0.0 if Comctl32.dll isn't installed at all:

void GetComctlVersion(DWORD &dwMajor, DWORD &dwMinor)

{

dwMajor = dwMinor = 0;

HINSTANCE hLib = ::LoadLibrary (_T ("Comctl32.dll"));

if (hLib != NULL) {

DLLGETVERSIONPROC pDllGetVersion =

(DLLGETVERSIONPROC) ::GetProcAddress (hLib, _T ("DllGetVersion"));

if (pDllGetVersion) { // IE 3.0 or higher

DLLVERSIONINFO dvi;

::ZeroMemory (&dvi, sizeof (dvi));

dvi.cbSize = sizeof (dvi);

HRESULT hr = (*pDllGetVersion) (&dvi);

if (SUCCEEDED (hr)) {

dwMajor = dvi.dwMajorVersion;

dwMinor = dvi.dwMinorVersion;

}

}

else { // Pre-IE 3.0

dwMajor = 4;

dwMinor = 0;

}

::FreeLibrary (hLib);

}

}

You also need a way to translate Internet Explorer version numbers into Comctl32.dll version numbers. Here's a table that will help:

Internet Explorer Version

Comctl32.dll Version

3.0

4.70

4.0

4.71

4.01

4.72

Now if I say that a certain feature requires Internet Explorer 3.0 or later and you want to determine at run time whether that feature is supported, you can do this:

DWORD dwMajor, dwMinor;

GetComctlVersion (dwMajor, dwMinor);

if ((dwMajor == 4 && dwMinor >= 70) ¦¦ dwMajor > 4) {

// The feature is supported.

}

else {

// The feature is not supported.

}

Yes, it's ugly. But it's the only option currently available.

Creating a Common Control

There are two ways to create a common control without resorting to API functions. The first method is to instantiate the corresponding MFC control class and call the resulting object's Create function, as demonstrated here:

#include <afxcmn.h>

CProgressCtrl wndProgress;

wndProgress.Create (WS_CHILD ¦ WS_VISIBLE ¦ WS_BORDER,

CRect (x1, y1, x2, y2), this, IDC_PROGRESS);

The header file Afxcmn.h contains the declarations for CProgressCtrl and other common control classes. The second method is to add a CONTROL statement to a dialog template. When the dialog box is created, the control is created, too. The following CONTROL statement creates a progress control in a dialog box:

CONTROL "", IDC_PROGRESS, PROGRESS_CLASS, WS_BORDER, 32, 32, 80, 16

When you create a common control this way, you can specify either the literal WNDCLASS name or its alias, whichever you prefer. The Visual C++ dialog editor writes CONTROL statements for you when you use it to add common controls to a dialog box.

Most of the common controls support their own window styles, which you can combine with WS_CHILD, WS_VISIBLE, and other standard window styles. The table below shows the "generic" common control styles that, at least in theory, aren't specific to any particular control type. As an MFC programmer, you'll rarely have occasion to manipulate these styles directly because many of them apply only to toolbars and status bars, and if you use CToolBar and CStatusBar instead of the more primitive CToolBarCtrl and CStatusBarCtrl classes to implement toolbars and status bars, the appropriate CCS styles are built in. These are by no means all the styles you can use with common controls. I'll point out control-specific styles when we examine individual control types.

Common Control Styles

Style

Description

CCS_TOP

Positions the control at the top of its parent's client area and matches the control's width to the width of its parent. Toolbars have this style by default.

CCS_BOTTOM

Positions the control at the bottom of its parent's client area and matches the control's width to the width of its parent. Status bars have this style by default.

CCS_LEFT*

Positions the control at the left end of its parent's client area.

CCS_RIGHT*

Positions the control at the right end of its parent's client area.

CCS_VERT*

Orients the control vertically rather than horizontally.

CCS_NOMOVEX*

Causes the control to resize and move itself vertically but not horizontally when its parent is resized.

CCS_NOMOVEY

Causes the control to resize and move itself horizontally but not vertically when its parent is resized. Header controls have this style by default.

CCS_NORESIZE

Prevents the control from resizing itself when the size of its parent changes. If this style is specified, the control assumes the width and height specified in the control rectangle.

CCS_NOPARENTALIGN

Prevents the control from sticking to the top or bottom of its parent's client area. A control with this style retains its position relative to the upper left corner of its parent's client area. If this style is combined with CCS_TOP or CCS_BOTTOM, the control assumes a default height but its width and position don't change when its parent is resized.

CCS_NODIVIDER

Eliminates the divider drawn at the top of a toolbar control.

CCS_ADJUSTABLE

Enables a toolbar control's built-in customization features. Double-clicking a toolbar of this type displays a Customize Toolbar dialog box.

* Requires Internet Explorer 3.0 or later

Once you've created a common control, you manipulate it using member functions of the corresponding control class. For controls created from dialog templates, you can use any of the techniques described in Chapter 8 to manufacture type-specific references for accessing a control's function and data members. For example, the following statement links a CProgressCtrl member variable named m_wndProgress to the progress control whose ID is IDC_PROGRESS:

DDX_Control (pDX, IDC_PROGRESS, m_wndProgress);

This statement must appear in a dialog class's DoDataExchange function. Rather than add the statement manually, you can use ClassWizard if you'd like. See Chapter 8 for a description of how to use ClassWizard to bind a member variable in a dialog class to a control in the dialog box.

When you use the common controls in an SDK-style application, you must call either ::InitCommonControls or the newer ::InitCommonControlsEx to load Comctl32.dll and register the controls' WNDCLASSes before creating the first control. In an MFC application, MFC calls these functions for you. It first tries to call ::InitCommonControlsEx. If the attempt fails because Internet Explorer 3.0 or later isn't installed (Internet Explorer adds ::InitCommonControlsEx to the Win32 API), MFC falls back and calls ::InitCommonControls, which is supported on any system running Windows 95 or higher or Windows NT 3.51 or higher.

MFC calls ::InitCommonControls(Ex) whenever a dialog box is created or a common control class's Create function is called. If for some reason you decide to create a common control or a dialog box that contains a common control using the Windows API instead of MFC, or if you create a common control with CreateEx instead of Create, you should call ::InitCommonControls or ::InitCommonControlsEx yourself. A good place to do that is in the main window's OnCreate handler or InitInstance, although you can defer the call until just before the control or dialog box is created if you'd prefer. It's not harmful to call ::InitCommonControls(Ex) multiple times during an application's lifetime.

Processing Notifications: The WM_NOTIFY Message

Unlike the classic controls, which send notifications to their parents using WM_COMMAND messages, most common controls package their notifications in WM_NOTIFY messages. A WM_NOTIFY message's wParam holds the child window ID of the control that sent the message, and lParam holds a pointer to either an NMHDR structure or a structure that's a superset of NMHDR. NMHDR is defined as follows:

typedef struct tagNMHDR {

HWND hwndFrom;

UINT idFrom;

UINT code;

} NMHDR;

hwndFrom holds the control's window handle, idFrom holds the control ID (the same value that's passed in wParam), and code specifies the notification code. The following notifications are transmitted by virtually all of the common controls.

Notification

Sent When

NM_CLICK

The control is clicked with the left mouse button.

NM_DBLCLK

The control is double-clicked with the left mouse button.

NM_RCLICK

The control is clicked with the right mouse button.

NM_RDBLCLK

The control is double-clicked with the right mouse button.

NM_RETURN

The Enter key is pressed while the control has the input focus.

NM_KILLFOCUS

The control loses the input focus.

NM_SETFOCUS

The control gains the input focus.

NM_OUTOFMEMORY

An operation on the control has failed because of insufficient memory.

Systems on which Internet Explorer 3.0 or later is installed support a richer assortment of NM notifications. For example, certain control types, including some of the original common controls that aren't unique to Internet Explorer but that are enhanced when Internet Explorer is installed, send NM_CUSTOMDRAW notifications so that their owners can customize their appearance. Others send NM_SETCURSOR notifications that their owners can use to apply custom cursors. The documentation for individual controls notes the "special" NM notifications, if any, that the controls send.

Most common controls define additional notification codes to signify control-specific events. For example, a tree view control notifies its parent when a subtree is expanded by sending it a WM_NOTIFY message with code equal to TVN_ITEMEXPANDED. lParam points to an NM_TREEVIEW structure, which contains the following data members:

typedef struct _NM_TREEVIEW {

NMHDR hdr;

UINT action;

TV_ITEM itemOld;

TV_ITEM itemNew;

POINT ptDrag;

} NM_TREEVIEW;

Notice that the structure's first member is an NMHDR structure, making NM_TREEVIEW a functional superset of NMHDR. The type of structure lParam points to depends on the type of control the notification came from. It sometimes even depends on the notification code. For instance, the lParam accompanying a TVN_GETDISPINFO notification from a tree view control points to a TV_DISPINFO structure, which is defined differently than NM_TREEVIEW is:

typedef struct _TV_DISPINFO {

NMHDR hdr;

TV_ITEM item;

} TV_DISPINFO;

How do you know what kind of pointer to cast lParam to? You start by casting to an NMHDR pointer and examining the notification code. Then, if necessary, you can recast to a more specific pointer type, as demonstrated here:

NMHDR* pnmh = (NMHDR*) lParam;

switch (pnmh->code) {

case TVN_ITEMEXPANDED:

NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pnmh;

// Process the notification.

break;

case TVN_GETDISPINFO:

NM_DISPINFO* pnmdi = (NM_DISPINFO*) pnmh;

// Process the notification.

break;

}

If the window that processes these notifications contains two or more tree view controls, it can examine the hwndFrom or idFrom field of the NMHDR structure to determine which control sent the notification.

switch statements like the one above are usually unnecessary in MFC applications, because notifications encapsulated in WM_NOTIFY messages are mapped to class member functions with ON_NOTIFY and ON_NOTIFY_RANGE macros. In addition, WM_NOTIFY notifications can be reflected to derived control classes using ON_NOTIFY_REFLECT. (MFC also supports extended forms of these macros named ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE, and ON_NOTIFY_REFLECT_EX.) The following message-map entries map TVN_ITEMEXPANDED and TVN_GETDISPINFO notifications from a tree view control whose ID is IDC_TREEVIEW to handling functions named OnItemExpanded and OnGetDispInfo:

ON_NOTIFY (TVN_ITEMEXPANDED, IDC_TREEVIEW, OnItemExpanded)

ON_NOTIFY (TVN_GETDISPINFO, IDC_TREEVIEW, OnGetDispInfo)

Casting to specific pointer types is performed inside the notification handlers:

void CMyWindow::OnItemExpanded (NMHDR* pnmh, LRESULT* pResult)

{

NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pnmh;

// Process the notification.

}

void CMyWindow::OnGetDispInfo (NMHDR* pnmh, LRESULT* pResult)

{

NM_DISPINFO* pnmdi = (NM_DISPINFO*) pnmh;

// Process the notification.

}

The pnmh parameter passed to an ON_NOTIFY handler is identical to the WM_NOTIFY message's lParam. The pResult parameter points to a 32-bit LRESULT variable that receives the handler's return value. Many notifications attach no meaning to the return value, in which case the handler can safely ignore pResult. But sometimes what happens after the handler returns depends on the value of *pResult. For example, you can prevent branches of a tree view control from being expanded by processing TVN_ITEMEXPANDING notifications and setting *pResult to a nonzero value. A 0 return value, on the other hand, allows the expansion to occur:

// In the message map

ON_NOTIFY (TVN_ITEMEXPANDING, IDC_TREEVIEW, OnItemExpanding)

void OnItemExpanding (NMHDR* pnmh, LRESULT* pResult)

{

NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pnmh;

if (...) {

*pResult = TRUE; // Under certain conditions, prevent

return; // the expansion from taking place.

}

*pResult = 0; // Allow the expansion to proceed.

}

A TVN_ITEMEXPANDING notification differs from a TVN_ITEMEXPANDED notification in that it is sent before an item in a tree view control is expanded, not after. As with the standard control types, you can ignore notifications you're not interested in and process only those that are meaningful to your application. Windows provides appropriate default responses for unhandled notifications.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有