Pre-record
These embedded classes are actually very early in the completion of the 2003 when I published the Code on the CodeProject, but the use of purple as a button border, causing a few boring ly where to quarrel about the gays problem, hehe, it seems not only the language to connect, The understanding of color should be in line with the West. Now just take this opportunity to tidy up the code, write an article to commemorate it.
The purpose of this article is to use ATL/WTL to make a dialog box that is the same as the Personality dialog box of "Creating an MFC Chapter with a personalized dialog box." ATL/WTL a set of template libraries, creating ATL/WTL applications inevitably uses the knowledge of C + + templates and multiple inheritance, and I hope you understand them before looking at this article. At the end of this article you can download the example code described in the load, compile the code need to install the WTL library, for more detailed information on WTL, please see orbit translated "WTL for MFC Programmers" series of articles, specific location in:Http://blog.csdn.net/orbit。
ATL and WTL have built a lightweight application framework, and ATL is strictly distinguishable in design-time interface definition and implementation, which is most noticeable in the design of the window class, similar to the Com,com interface definition and implementation being completely separate (or there may be multiple implementations). ATL has an interface specifically designed for windows that can do all of the window operations, which is CWindow. It is actually the wrapper class for the HWND operation, encapsulating almost all the window APIs with the HWND handle as the first parameter, for example: SetWindowText () and DestroyWindow (). The implementation of a window procedure in an ATL class is CWindowImpl. CWindowImpl contains all the window implementation code, such as: Window class registration, window sub-class, message map and basic WindowProc () function, can see this and MFC design is very different, MFC put all the code in a CWnd class.
Because ATL and MFC are all libraries that are applied to the Windows platform, they are able to respond to and process the window messages sent by the system, except that ATL and MFC assign different ways of assigning messages, resulting in differences in coding. These differences are not insurmountable, ATL also defines some macros similar to MFC to process and dispatch messages, and each ATL window class uses a message map or message map chain to correlate message handlers with specific messages, which is similar to MFC's approach. The small difference is that the parameters of the message response function, MFC internal interpretation of Windows message parameters, that is, wparam and lparam, the parameters passed to the message response function is relatively friendly, The message response function of ATL is to pass wparam and lparam to the message response function, and programmers who are unfamiliar with Windows messages may be confused. If you are familiar with the template mechanism of C + +, and are willing to keep looking at MSDN, it is easy to "translate" MFC's window class into Atl/wtl window class, for example, the Cwzbuttonimpl class used in this article is from the "MFC sister article" The Csmbutton class in the example code is translated.
Before you start creating a Personality dialog box with ATL/WTL, you'll also introduce the embedded classes (Mix-in Class) that are commonly used in ATL. Another notable difference in ATL is that any C + + class can respond to messages, and MFC simply assigns the message response task to the CWnd class and the CCmdTarget class, plus several classes with the PreTranslateMessage () method. This feature of ATL allows us to write so-called "embedded classes" and add attributes to our windows simply by adding the class to the inheritance list. A basic class with a message-map chain is typically a template class that makes the class of a derived class A parameter to the template so that it can access members in the derived class, such as M_hwnd (an HWND member in the CWindow Class). Let's look at an example of an embedded class that draws the background of a window by responding to a WM_ERASEBKGND message:
Template <class T, Colorref t_crbrushcolor>
Class Cpaintbkgnd:public CMessageMap
{
Public
Cpaintbkgnd () {m_hbrbkgnd = CreateSolidBrush (T_crbrushcolor);}
~cpaintbkgnd () {DeleteObject (M_HBRBKGND);}
Begin_msg_map (CPAINTBKGND)
Message_handler (WM_ERASEBKGND, OnEraseBkgnd)
End_msg_map ()
LRESULT OnEraseBkgnd (UINT umsg, WPARAM WPARAM, LPARAM LPARAM, bool& bhandled)
{
t* PT = static_cast<t*> (this);
HDC DC = (HDC) WParam;
RECT rcclient;
Pt->getclientrect (&rcclient);
FillRect (DC, &rcclient, M_HBRBKGND);
return 1; We painted the background
}
Protected
Hbrush M_hbrbkgnd;
};
Let's take a look at this new class. First, Cpaintbkgnd has two template parameters: the name of the derived class using CPAINTBKGND and the color used to draw the window background. (The t_ prefix is often used as a prefix to the template parameters of the template class) Cpaintbkgnd is also derived from CMessageMap, which is not necessary because all classes that need to respond to the message simply use the BEGIN_MSG_MAP macro, which is sufficient. So you might see some other example code for embedded classes that are not derived from that base class.
Constructors and destructors are fairly simple, just creating and destroying Windows brushes, which are determined by the parameter T_crbrushcolor color. Next is the message map chain, which responds to the WM_ERASEBKGND message, and finally fills the background of the window with a brush created by the response function OnEraseBkgnd () with the constructor function. There are two things you need to do to use this embedded class in our window: first, add it to the inheritance list:
Class Cmywindow:public Cwindowimpl<cmywindow, CWindow, Cframewintraits>,
Public Cpaintbkgnd<cmywindow, RGB (0,0,255) >
Second, you need CMyWindow to pass the message to CPAINTBKGND, which is to link it to the message map chain and add the CHAIN_MSG_MAP macro to the CMyWindow message map chain:
typedef Cpaintbkgnd<cmywindow, RGB (0,0,255) > cpaintbkgndbase;
begin_msg_map (CMyWindow)
message_handler (Wm_close, OnClose)
message_handler (Wm_destroy, OnDestroy)
command_handler (Idc_about, onabout)
CHAIN_MSG_MAP (cpaintbkgndbase)
End_msg_map ()
Any messages that are not processed by CMyWindow are passed to Cpaintbkgnd. It should be noted that Wm_close,wm_destroy and idc_about messages will not be passed, as these messages will be aborted once the lookup of the message map chain is processed. You can use multiple embedded classes in an inheritance list, each with an Chain_msg_map macro, so that the message map chain will pass the message to it. This differs from MFC in that the CWnd-derived class of MFC can have only one base class, and MFC automatically passes the message to the base class.
With the knowledge of ATL message processing and embedding classes, you can start creating a ATL/WTL Color dialog box. One of the simplest ways to change the background color of a dialog box is to call the Cwinapp::setdialogbkcolor () function in the "Create an MFC chapter of a personalized dialog", but unfortunately, ATL/WTL does not provide this method, at least ATL 7.1 and WTL 7.1 is the case. But it doesn't matter, we can make the color dialog by processing Some special window drawing message to MFC, and the ATL/WTL way is more flexible, we will see later.
The first is to modify the background of the dialog box, this only needs to process the WM_ERASEBKGND message, it can be done in the ATL window, but ATL can use more flexible embedded classes, the aforementioned cpaintbkgnd is such an embedded class. Using an embedded class to encapsulate the handler function of the WM_ERASEBKGND message into the Cpaintbkgnd class avoids the excessive bloat of the Cmaindlg code, and also makes the dialog box that creates the same background more so that it does not need to copy the code from ONERASEBKGND to the new dialog class. Just add the CPAINTBKGND to the integration list for the new class:
Class Cmaindlg:public Cdialogimpl<cmaindlg>
Public Cpaintbkgnd<cmaindlg, RGB (0,0,255) >
So Cmaindlg has a blue background, change cpaintbkgnd template parameters T_crbrushcolor can customize the dialog box different colors, the following code makes the dialog box has a light green background:
Class Cmaindlg:public Cdialogimpl<cmaindlg>
Public Cpaintbkgnd<cmaindlg, RGB (215,241,215) >
Figure 1: Dialog box with CPAINTBKGND
As with WM_ERASEBKGND messages in MFC, the background color of the control has not changed, and the following article describes how to respond to wm_ctlcolorxxx messages under the ATL/WTL framework.
MFC maps All WM_CTLCOLORXXX series messages to wm_ctlcolor messages, but distinguishes them by the parameters of the OnCtlColor () function, but WM_CTLCOLORDLG messages are not mapped to Wm_ctlcolor, Because MFC has done other processing for WM_CTLCOLORDLG messages, if you are willing to trace the code of Cwinapp::setdialogbkcolor () you will see how MFC handles Wm_ctlcolordlg messages. Also formally because MFC to Wm_ctlcolordlg "another plan", make this article "MFC sister article" in order to change the background color of the dialog box has to deal with the WM_ERASEBKGND message. However, using ATL/WTL does not require additional processing of WM_ERASEBKGND messages because it is easier to process WM_CTLCOLORDLG notification messages. ATL/WTL does not handle WM_CTLCOLORXXX series messages uniformly, but if centralized processing of these messages simplifies code writing and facilitates interchangeability with MFC code, we can also map them to a message handler function. In fact, this is what the cctrlcolor is going to be about.
The following is the use of cctrlcolor, which does not continue to use CPAINTBKGND, because WM_CTLCOLORDLG notification messages are processed in Cctrlcolor.
Figure 2: Dialog box with Cctrlcolor
Using a bitmap background in a dialog box is also simple, as long as you write a bitmap-like class as you cpaintbkgnd, here's a simple example:
template <class T, UINT ubitmapid>
Class Cbitmapbkgnd:public CMessageMap
{
Public:
cbitmapbkgnd () {m_bitmap.loadbitmap (ubitmapid);}
~cbitmapbkgnd () {m_bitmap.deleteobject ();}
begin_msg_map (CPAINTBKGND)
message_handler (WM_ Erasebkgnd, OnEraseBkgnd)
end_msg_map ()
lresult onerasebkgnd (UINT umsg, WPARAM WPARAM, LPARAM LPARAM, bool& bhandled)
{
T* PT = static_cast<t*> (this);
HDC hdc = (hdc) WParam;
rect rcclient;
pt->getclientrect (&rcclient);
bitmap BM;
m_bitmap.getbitmap (&BM);
&NBSP;&NBSP;CDC MEMDC;
memdc.createcompatibledc (HDC);
hbitmap holdbmp = Memdc.selectbitmap (M_bitmap);
stretchblt (hdc,0,0,rcclient.right-rcclient.left,rcclient.bottom-rcclient.top,memdc,0,0, Bm.bmwidth,bm.bmheight,srccopy);
memdc.selectbitmap (holdbmp);
memdc.deletedc ();
return 1; //We painted the background
}
Protected
CBitmap M_bitmap;
};
Compared to CPAINTBKGND, CBITMAPBKGND only modifies the code of the second template parameter and the OnEraseBkgnd () function, and because the bitmap is used as the background of the dialog box, the controls in the dialog box are processed WM_ CTLCOLORXXX Series message should return an empty brush instead of the default background color brush, which requires a custom processing WM_CTLCOLORXXX series of messages embedded class, this article uses the Cctrlhollowcolor and CBITMAPBKGND with , but Cctrlhollowcolor is too simple, it can only be used in the examples in this article, and if there are more controls in the dialog box, you need to modify the code of the Cctrlhollowcolor class. Here is the effect of using the bitmap background:
Figure 3: Dialog box with bitmap backgrounds
Now it's time to think about the button, like the MFC sister article in this article, the WTL example of this article also uses a self-drawing button class. The previous article has mentioned, it is actually from Csmbutton "transplant" come over, you certainly think there are some different, that is because Cwzbuttonimpl used the characteristics of ATL, that is, the use of WTL embedded class: Cownerdraw. In the MFC button Class Csmbutton, the Wm_drawitem message was made by MFC internal mapping, the final button mapping work to the virtual function DrawItem (), which is the use of C + + polymorphism mechanism. ATL/WTL does not use virtual functions, multiple inheritance and embedding classes is a more flexible way than MFC to avoid using virtual functions, which makes ATL/WTL's window objects occupy less memory than MFC's Window objects. As long as the Cownerdraw class is added to the integration list of the window class, it is possible to move Csmbutton::D Rawitem () to Cwzbuttonimpl, and the following is the complete declaration of the Cwzbuttonimpl class, which can be seen as a window class. Interfaces with CButton:
Class Cwzbuttonimpl:public Cwindowimpl<cwzbuttonimpl, Cbutton>,public cownerdraw<cwzbuttonimpl>
The use of Cwzbuttonimpl can differ greatly from MFC in ATL, which can only be associated with a control through the SubclassWindow () method, although WTL is the same as MFC, since ATL also implements DDE/DDV similar to MFC.
If there are many buttons in a dialog box, it can be a hassle to add a link to it, especially if you need to remove a button from the dialog box. Here I would like to introduce a useful helper class: Cbuttonhelp. Cbuttonhelp is a template class whose function is to enumerate all the controls in the dialog box when the dialog is initialized, to find out which button controls are in the button class (subclassing) as specified by the template parameters. The following is a declaration of the Cbuttonhelp class:
Template <class T, class t_buttonclass>
Class Cbuttonhelp
The first template parameter is the window class, the second template parameter is the button class, by replacing the template parameter T_buttonclass can use different style buttons in different dialogs, the following example is the declaration of the main dialog box in the example code used in this article, He uses Cwzbuttonimpl to subclass the button controls:
Class Cmaindlg:public Cdialogimpl<cmaindlg>, public cctrlcolor<cmaindlg>,
Public cbuttonhelp<cmaindlg,cwzbuttonimpl>
Assuming there is also a self-drawing button class Cbitmapbuttonimpl, the following declaration will enable the Cbmpdlg dialog box to have a different style of self-drawing button:
Class Cbmpdlg:public Cdialogimpl<cbmpdlg>, public cctrlcolor<cbmpdlg>,
Public cbuttonhelp<cbmpdlg,cbitmapbuttonimpl>
The Cbuttonhelp class has three main functions, one is subclassallbuttons (), this function iterates through all the child controls of the dialog, subclasses of which have pushbutton-style buttons, Subclassbutton () sub-class the specified button, Unsubclassbutton () is the inverse process of Subclassbutton (). Here are the effects after using Cbuttonhelp and Cwzbuttonimpl:
Figure 4: Dialog box after using the Self-drawing button
At this point, this article has used ATL/WTL implementation of the MFC example of all the functions, through the comparison can see the advantages of each of the two frameworks, the same problem of the solution is the same, but the way the code is different. The example code used in this article can be downloaded in the link below.
Http://blog.csdn.net/images/blog_csdn_net/orbit/demo2.zip
Transferred from: http://blog.csdn.net/orbit/article/details/485125
Create a personalized dialog box ATL/WTL