Window TraitsIn the previous article we specified window styles by passing the style and extended style information to CWindowImpl's Create() function. [listing 2.3] mainwnd.Create(NULL,CWindow::rcDefault,_T("Main Window"), WS_OVERLAPPEDWINDOW); The Windows Template Library provides another method of specifying these styles: window traits. Window traits work by taking style information and storing it in an instance of a template class. This is done though a template class called CWinTraits. The template takes two DWORD parameters, the style and extended style, and provides methods for accessing them. The definition of CWinTraits is listed below. [listing 2.4] template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0> class CWinTraits { public: static DWORD GetWndStyle(DWORD dwStyle) { return dwStyle == 0 ? t_dwStyle : dwStyle; } static DWORD GetWndExStyle(DWORD dwExStyle) { return dwExStyle == 0 ? t_dwExStyle : dwExStyle; } }; The purpose of the GetWndStyle() and GetWndExStyle() functions is rather obvious but their implementation is a bit cryptic. If the value passed to GetWndStyle() and GetWndExStyle() is zero they return the stored style information. If the value passed is not zero, they return the passed value. Admittedly, this seems a little silly. Why not simply return the stored values, drop the parameter, and be done with it? The answer lies in the way the class is used in the WTL libraries. Below is CWindowImpl's Create method. [listing 2.5] HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) { if (T::GetWndClassInfo().m_lpszOrigName == NULL) T::GetWndClassInfo().m_lpszOrigName = GetWndClassName(); ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, atom, lpCreateParam); } Notice that the dwStyle and dwExStyle parameters have a default value: zero. Also notice that dwStyle and dwExStyle are passed to GetWndStyle() and GetWndExStyle(), set to the value returned by GetWndStyle() and GetWndExStyle(), and then passed on to CWindowImplBaseT's Create() method. With this set up, if no styles are specified in the call to CWindowImpl::Create() the styles stored in the trait class are used. If styles are passed to CWindowImpl::Create() they override the traits. This useful feature allows us to attach a set of default window styles to our newly implemented window, while users of this new window retain the ability easily override these styles if they happen to not suit the particular instance he or she is creating. There are times, however, when you don't necessarily want users to replace the trait styles. You may wish to use the trait styles as a set of base styles and only give users of your window class the ability to add a style or two to this minimum set. The CWinTraitsOR class provides this functionality. Simply use it in place of CWinTraits. To sum up, CWindowImpl derived classes that use a CWinTraits instance for the TWinTraits template parameter will override the stored styles if styles are passed to Create(). CWindowImpl derived classes that use a CWinTraitsOR instance for the TWinTraits template parameter will add any styles passed via Create() to the stored styles and this combined set of styles will be used to create the window. The WTL library also provides a handful of predefined trait classes. You'll find them used by various window implementation classes provided by the library. For the sake of completeness I've listed their definition below. [listing 2.6] typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0> CControlWinTraits; typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CFrameWinTraits; typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD> CMDIChildWinTraits; typedef CWinTraits<0, 0> CNullTraits; Now that we have a thorough understanding of window traits, let's create a trait class for CDxWindowImpl. Make the following changes to CDxWindowImpl.h: [listing 2.7] #ifndef __ATLWIN_H__ #error CDxWindowImpl.h requires atlwin.h to be included first #endif typedef CWinTraits<WS_OVERLAPPEDWINDOW,0> CDxAppWinTraits; template <class T, class TBase = CWindow, class TWinTraits = CDxAppWinTraits > class CDxWindowImpl : public CWindowImpl<T,TBase, TWinTraits > { public: BEGIN_MSG_MAP(CDxWindowImpl) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) END_MSG_MAP() LRESULT OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { PostQuitMessage(0); bHandled = FALSE; return 0; } }; With these changes in place the call to Create() in Main.cpp no longer needs window styles passed to it. At this point rebuilding the project should produce an executable that creates and displays a window. |
|