Stingray® Foundation : Chapter 12 Developing Applications : Windowing Classes
Windowing Classes
After the application class, the second component within an SFL-based application is the window. SFL contains several classes that encapsulate various types of windows. These types of windows include container windows, frame windows, client windows and MDI windows. Following is a brief overview of each.
Container Windows
One of SFL’s more useful features is a Layout Manager. Sometimes you want to have the presentation of your application behave in certain ways as the application’s window is sized. SFL has classes to manage various layout algorithms. For example, when you program a toolbar into your application’s main window, sometimes you want the toolbar to stick close to the border of the application. Or perhaps you’d like the controls on a dialog box to scale as the window is sized. These layout algorithms are already implemented within SFL. The advantage of the Layout Manager is that they’re much more flexible than MFC’s hard-wired docking window management architecture.
To support the layout algorithms, SFL introduces several window classes that can contain layout plug-ins. Layout plug-ins are layout manager components that have hooks into the ATL messaging architecture to receive messages like WM_SIZE and WM_MOVE.
SFL’s container window classes include CContainerImplBase, CContainerWindowImpl, CContainerDialogImpl.
CContainerImplBase
CContainerImplBase is the main class, mixing a window class with one of SFL’s layout plug-ins. Example 104 shows CContainerImplBase.
Example 104 – CContainerImplBase
template <typename _Derived,
typename _Traits,
typename _BaseImpl,
typename _LayoutPlugin >
class CContainerImplBase:
public _BaseImpl,
public _LayoutPlugin
{
};
CContainerImplBase is a template class, taking four parameters: the bottom-most derived class, the window creation flags, the base implementation class, and the layout plug-in to be used. CContainerImpl is almost never used by itself, serving instead as a base class for the other layout container windows.
CContainerWindowImpl
CContainerImplBase makes its first appearance in the declaration of -CContainerWindowImpl. Example 105 shows the definition of CContainerWindowImpl.
Example 105 – CContainerWindowImpl
template <typename _Derived,
typename _Traits,
typename _Base = CWindow>
class CContainerWindowImpl :
public CContainerImplBase<_Derived, _Traits,
CWindowImpl<_Derived, _Base, _Traits>,
foundation::CLayoutManager<_Derived> >
{
};
CContainerWindowImpl defines a CContainerImplBase-derived class using ATL’s CWindow class and SFL’s CLayoutManager class.
CContainerDialogImpl
CContainerDialogImpl is useful for adding layout management to dialogs. Example 106 shows CContainerDialogImpl.
Example 106 – CContainerDialogImpl
template <typename _Derived>
class CContainerDialogImpl :
public CContainerImplBase<_Derived,
CNullTraits, CAxDialogImpl<_Derived>,
foundation::CLayoutManager<_Derived, WM_INITDIALOG> >
{
};
CContainerDialogImpl adds layout management to ATL’s CAxDialogImpl class.
The container window classes aren’t intended to be used by themselves but instead are intended to add the Layout Manager layer to SFL by mixing with real window classes—that is, frame windows, client windows, dialog windows, and MDI windows.
Frame Windows
Frame windows are usually intended to be the main window in an SDI application. SFL’s CFrameWindowImpl serves this purpose. CFrameWindowImpl derives from SFL’s container window and so obtains the benefit of the Layout Manager automatically. Example 107 shows the definition of SFL’s CFrameWindowImpl class.
Example 107 – SFL’s CFrameWindowImpl class
template <typename _Derived,
unsigned int _nResource = 0,
typename _Traits = CFrameWinTraits,
typename _Base = CWindow>
class CFrameWindowImpl:
public CContainerWindowImpl<_Derived,
_Traits,
_Base >
{
typedef CFrameWindowImpl<_Derived, _nResource, _Traits, _Base>
thisClass;
typedef CContainerWindowImpl<_Derived, _Traits, _Base >
_windowBase;
 
};
SFL’s CFrameWindowImpl class handles the WM_DESTROY and WM_INITMENUPOPUP messages. CFrameWindowImpl handles the WM_DESTROY by posting the quit message if the frame window is not a child window or a pop up window. CFrameWindowImpl handles the WM_INITMENUPOPUP message by issuing a user interface update notification.
CFrameWindowImpl includes everything necessary to create and show a frame window on the screen. Notice that the definition takes four parameters. The first template parameter, _Derived, is the only one that you must provide. The other templates specify the resource identifier (for the menu, the accelerator table, the caption string, and icon), the creation flags, and the base window class. CFrameWindowImpl defaults to the number zero for the resource id, to ATL’s CFrameWinTraits as the window creation flags, and to ATL’s CWindow class as the base window class. This combination generates the infrastructure for creating a plain vanilla frame window.
Example 108 shows how to define a frame window for your application.
Example 108 – Defining a derived frame window class
class CMyFrame :
public foundation::CFrameWindowImpl<CMyFrame, IDR_HelloSFL>
{
};
CFrameWindowImpl also has a create function which maps to the Win32 -CreateWindowEx API. Example 109 shows CFrameWindowImpl’s Create() function.
Example 109 – CFrameWindowImpl::Create()
HWND CFrameWindowImpl::Create (HWND hWndParent,
RECT& rcPos,
LPCTSTR lpszWindowName = 0,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
HMENU hMenu = 0, LPVOID lpCreateParam = 0)
You don’t usually need to override CFrameWindowImp::Create(). As long as your derived window class includes this signature for the Create() function, SFL’s message loop class will create the window automatically.
Client Windows
Sometimes your application architecture calls for non-frame windows. For example, many applications require the rendering and drawing code to be separate from the frame. SFL supports this requirement through its client windows. SFL defines its client windows through a class named CClientWindowImpl. Client windows are usually children of frame windows. Example 110 shows SFL’s client window class.
Example 110 – SFL’s CClientWindowImpl class
template <typename _Derived,
typename _Traits = CClientWindowTraits,
typename _Base = ATL::CWindowImpl<_Derived,
CWindow,
_Traits> >
class CClientWindowImpl:
public _Base
{
public:
typedef CClientWindowImpl<_Derived, _Base, _Traits > _thisClass;
typedef _Base _windowBase;
};
Also a template class, CClientWindowImpl takes three template parameters: the ultimately derived class, the window creation flags (the window traits), and a base class. Notice that the default base class for CClientWindowImpl is ATL’s -CWindowImpl class and that the default creation flags are SFL’s client window creation flags. Example 111 shows SFL’s CClientWindow traits flags.
Example 111 – SLF’s CClientWindow traits flags
typedef CWinTraits<WS_CLIPCHILDREN |
WS_CLIPSIBLINGS |
WS_CHILD |
WS_VISIBLE,
WS_EX_STATICEDGE> CClientWindowTraits;
SFL’s client window class is usually mixed in with other classes. For example, SFL’s Model-View-Controller architecture uses CClientWindow as one of -CMvcClientViewport’s base classes, as illustrated in Example 112.
Example 112 – SFL’s CMvcClientViewport
class CMvcClientViewport : public CClientWindowImpl<T>,
public _Viewport,
public CEventRouterMap<T>,
public IvisualWindow
{
};
When developing applications, this class is often useful when you need to embed one window into another window.
Next you’ll examine SFL’s Multiple Document Interface support.
MDI Support
SFL provides support for developing Multiple Document Interface (MDI) applications. MDI applications are more complex than SDI applications because MDI applications have to be built to handle multiple open windows and documents at once. The MDI specification stipulates several kinds of windows including the main MDI Frame window, the MDI Client window, and the MDI Child window. Figure 14 shows the MDI Architecture.
Figure 14 – MDI Architecture
SFL hides the complexities behind MDI applications using a set of classes. SFL’s MDI classes include CMDIChildImpl, CMDIClientWindow, CMDIFrame, and CMDIFrameImpl. Following is an explanation of each class.
CMDIChildImpl
SFL’s CMDIChildImpl class manages the MDI child’s menu, the WM_MDIACTIVATE message to set up that menu within the MDI frame, and the special steps involved in creating an MDI child window. CMDIChildImpl is usually used as a base class for MDI child windows within your application. CMDIChildImpl is a template class taking the derived class as the first parameter and the menu resource as the second parameter. Example 113 shows an example of using CMDIChildImpl as a base class.
Example 113 – SFL’s CMDIChildImpl
class CMyMDIChild : public CMDIChildImpl<CMyMDIChild,
IDR_SFLMDISimpleApp>
{
};
CMDIClientWindow
An MDI application needs to contain an MDI client window within the main frame window. The job of the MDI client window is to manage SFL’s MDI child window creation. You usually don’t need to use this class explicitly—the class is usually mixed into the frame window.
CMDIFrame
The job of SFL’s CMDIFrame class is to frame an MDI application and manage the application’s MDI-ness. This means being able to perform such functions as finding the currently active MDI child window, toggling through the application’s windows, cascading the windows, and tiling the windows. CMDIFrame is a template class taking a single template parameter, the MDI client window to use. Example 114 shows the declaration of SFL’s CMDIFrame class.
Example 114 – SFL’s CMDIFrame class
template <typename _MDIClient = CMDIClientWindow<> >
class CMDIFrame:
public CWindow
{
protected:
typedef _MDIClient CMDIClientWindow;
 
public:
CMDIClientWindow m_wndClient;
};
Notice that CMDIFrame uses CMDIClientWindow as the default MDI client window. CMDIFrame is usually mixed into SFL’s MDI architecture via CMDIFrameImpl.
CMDIFrameImpl
The CMDIFrame class is still an intermediate layer in the MDI-ness of an application. The final layer in an MDI application is usually CMDIFrameImpl. Example 115 shows SFL’s CMDIFrameImpl class.
Example 115 – SFL’s CMDIFrameImpl class
template <typename _Derived,
unsigned int _nResource,
typename _Traits = CFrameWinTraits,
typename _MDIClient = CMDIClientWindow<>,
typename _Base = CMDIFrame<_MDIClient> >
class CMDIFrameImpl:
public CFrameWindowImpl<_Derived,
_nResource,
_Traits,
_Base>
{
};
The first template parameter is the ultimately-derived class. The second parameter represents the resource id. The window creation flags are passed in as the third template parameter, defaulting to the ATL’s CFrameWindowTraits class. The MDI client window is passed as the fourth parameter, defaulting to SFL’s -CMDIClientWindow. The final parameter is the base class, which defaults to SFL’s CMDIFrame class.
CMDIFrameImpl is meant to be the base class for the main frame window in an MDI application. Example 116 shows how to declare a main MDI frame window using CMDIFrameImpl.
Example 116 – Using SFL’s CMDIFrameImpl class
class CMainFrame :
public foundation::CMDIFrameImpl<CMainFrame, IDR_MAINFRAME>,
public foundation::CMDIMessagePreTranslator<CMainFrame>,
{
public:
typedef foundation::CMDIFrameImpl<CMainFrame, IDR_MAINFRAME>
_WindowBase;
{
};
There is one final note concerning the MDI frame window—its message preprocessing capabilities (the PreTranslation facilities). Every MDI Frame must derive from CMDIMessagePreTranslator if it wants the MDI accelerators to work.
Common Dialogs
In the early days of Windows programming, developers had to write their own versions of dialog boxes for opening files, saving files, finding and replacing strings in a document, and choosing fonts and colors. Windows 3.1 introduced API functions for creating these common dialog boxes. SFL wraps the Windows common dialog box API to make common dialogs much easier to manage. Here you’ll survey SFL’s common dialog box classes, including the COpenFileDialog and CSaveAsFileDialog classes, the CFontDialog class, the CColorDialog class, and the CFindDialog and CReplaceDialog classes.
COpenFileDialog and CSaveAsFileDialog
SFL contains implementations of the common file management dialog boxes. Both COpenFileDialog and CSaveAsFileDialog inherit from CFileDialogImpl. -CFileDialogImpl serves as the base class for SFL’s common file dialog boxes. CFileDialogImpl inherits from ATL’s CDialogImplBase and so has the normal dialog box functionality. CFileDialogImpl has a member variable of type OPENFILENAME named m_ofn, which the file open and file save dialog boxes use to pass to the file dialog API functions. In addition, CFileDialogImpl has a boolean member variable named m_bOpenFileDialog. Both COpenFileDialog and CSaveAsFileDialog override the DoModal() function. DoModal() simply checks this flag to decide whether to call GetOpenFileName() or GetSaveFileName() API functions.
Example 117 shows how to use COpenFileDialog to get a file name and path.
Example 117 – Using COpenFileDialog
void DoFileOpen()
{
COpenFileDialog dlg("txt",
"Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0");
if (dlg.DoModal() != IDCANCEL) {
ATLTRACE("Complete file name is %s\r\n", dlg.GetFileName());
ATLTRACE("File name is %s\r\n", dlg.GetFileTitle());
}
}
Example 118 shows how to use CSaveAsFileDialog to get a file name and path.
Example 118 – Using CSaveAsFileDialog
void DofileSave()
{
CSaveFileDialog dlg("txt",
"Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0");
if (dlg.DoModal() != IDCANCEL) {
ATLTRACE("Complete file name is %s\r\n", dlg.GetFileName());
ATLTRACE("File name is %s\r\n", dlg.GetFileTitle());
}
}
CFontDialog
The CFontDialog class wraps the standard Windows font-selection dialog box into your application. A CFontDialog object is a dialog box with a list of fonts currently installed in the system. The user can select a particular font from the list.
To construct a CFontDialog object, use the provided constructor, or derive a new subclass and use your own custom constructor.
The CFontDialog contains a data member of type CHOOSEFONT named m_cf. Once a CFontDialog object has been constructed, you can use the m_cf structure to initialize the values or states of controls in the dialog box. For more information on this structure, see the Win32 SDK documentation.
After initializing the dialog object’s controls, call the DoModal() member function to display the dialog box and allow the user to select a font. DoModal() calls the standard Windows ChooseFont() API function. DoModal() returns whether the user selected the OK (IDOK) or Cancel (IDCANCEL) button.
If DoModal() returns IDOK, you can use one of CFontDialog’s member functions to retrieve the information input by the user. You can also use m_cf directly.
Example 119 shows how to use the font dialog.
Example 119 – Using CFontDialog
void DoFontSel() {
LOGFONT lf;
CFontDialog dlg(&lf);
if (dlg.DoModal() != IDCANCEL) {
LPCTSTR szFaceName;
szFaceName = GetFaceName();
LPCTSTR szStyleName;
szStyleName = GetStyleName();
}
}
CColorDialog
The CColorDialog class wraps the standard Windows color-selection dialog box. A CColorDialog object is a dialog box with a list of colors that are defined for the display system. The user can select or create a particular color from the list, which is then reported back to the application when the dialog box exits.
To construct a CColorDialog object, use the provided constructor or derive a new class and use your own custom constructor.
The CColorDialog has a member variable of type CHOOSECOLOR named m_cc. Once the dialog box has been constructed, you can set or modify any values in the m_cc structure to initialize the values of the dialog box’s controls.
After initializing the dialog box’s controls, call the DoModal() member function to display the dialog box and allow the user to select a color. DoModal() simply calls the ChooseColor() Windows API to show the standard color dialog box.
If DoModal() returns IDOK, CColorDialog’s m_cc member contains the information input by the user.
Example 120 shows how to use CColorDialog.
Example 120 – Using CColorDialog
void DoColorSel() {
CColorDialog coldlg(RGB(0xCC, 0x0c, 0x0c), CC_FULLOPEN |
CC_RGBINIT);
if (coldlg.DoModal() != IDCANCEL) {
COLORREF color;
color = coldlg.GetColor();
}
}
CFindDialog and CReplaceDialog
CFindDialog and CReplaceDialog wrap the standard replace dialog boxes. Both these dialog boxes are modeless (as opposed to a normal modal dialog box). These dialog boxes are usually created on the heap instead of stack. Both operate in a similar fashion. The CFindDialog lets you type in a string for which to search. The dialog box then calls back to the parent window every time the user clicks on the Find button. The application then takes the string typed in by the user and tries to find it within the document. The CReplaceDialog works in the same fashion, except the replace dialog also includes a field for typing a replacement string. Example 121 shows a frame class that uses the find and replace dialog boxes.
Example 121 – Using the CFindDialog and the CReplaceDialog common dialog boxes
class CMainFrame :
public CFrameWindowImpl<CMainFrame, IDR_UseCommonDlgs>
{
public:
typedef CFrameWindowImpl<CMainFrame, IDR_UseCommonDlgs>
_BaseClass;
 
BEGIN_MSG_MAP(CMainFrame)
COMMAND_ID_HANDLER(ID_EDIT_FONTDIALOG, OnFontDialog)
COMMAND_ID_HANDLER(ID_EDIT_FINDDIALOG, OnFindDialog)
COMMAND_ID_HANDLER(ID_EDIT_FINDREPLACEDIALOG, OnReplaceDialog)
CHAIN_MSG_MAP(_BaseClass)
END_MSG_MAP()
 
LRESULT OnFindDialog(WORD, WORD, HWND, BOOL&)
{
CFindDialog *dlg = new CFindDialog;
dlg->Create("What's up Doc?");
return 0;
}
 
LRESULT OnReplaceDialog(WORD, WORD, HWND, BOOL&)
{
CReplaceDialog *dlg = new CReplaceDialog;
dlg->Create("What's up Doc?", "We really mean it");
return 0;
}
 
LRESULT OnFindReplace(UINT , WPARAM , LPARAM lParam, BOOL& )
{
OutputDebugString("On Find Replace Notification\n");
CReplaceDialog* pDlg = CReplaceDialog::GetNotifier(lParam);
string sString;
 
sString = pDlg->m_szFindWhat;
// or do this...
sString = pDlg->GetFindString();
 
return 0;
}
};
This frame window class responds to the Find and Replace menu commands by creating and showing the appropriate dialog box. Each time the user hits the Find or Replace button, the common dialog box calls back to the frame window. Then the frame window can do whatever it needs to do with the find and replace strings.