WTL Extension library for Smartphone
By Ilya Manin, March 17, 2004.
Download
Introduction
Smartphone UI concepts are different from desktop Windows UI concepts.
For example, all topmost windows must be in full screen mode and
many dialogs must have a menu bar at bottom of screen. It may take much effort to
implement these Smartphone-specific elements in a WTL project. To simplify this task
we have developed WtlEx library. For now it includes classes to work with
dialogs and property sheets. We expect to add more useful classes in the fufure.
The library requires WTL 7.1, which you can download from
Microsoft site.
Library Contents
- CFakeDialogImpl is similar to CDialogImpl from WTL, but doesn't require a dialog
resource. Complex dialogs are very rarely used on Smartphone. Often you need to create a
dialog with one control (for example List View or Tree View). CFakeDialogImpl class enables
to use fully functional dialog box without creating a new resource. This class doesn't have a
Smartphone OS specific and can be use on other Win32 platforms.
- CSPDialogExt is a basic class of WtlEx library. The class provides support for menu bar
creating, bold font for static controls, handling of hardware key VK_TBACK in edit controls
and many other functions for Smartphone style dialogs.
- CSPDialogAuto, This class is a specialization of CSPDialogExt. It sets frequently used
parameters for CSPDialogExt.
- CSPSimpleDialog is similar to CSimpleDialog from WTL, but includes all additional
functionality of CSPDialogExt class.
- CSPPropertySheet and CSPPropertyPageImpl classes are similar to CPropertyPage and
CPropertySheet from WTL or MFC. These classes enable to create property sheets in
Smartphone style (property sheet shows a list of available pages and the user can invoke
any page by selecting it in the list and hitting action or using page number key).
- CSPSimplePropertyPage is similar to CSPSimpleDialog, but can be used with
CSPPropertySheet to create a property page without inheriting a new class for it.
- CSPListViewCtrl. This class has been published in
"Creating list view a-la "Programs"
list on Smartphone 2002" article. This version of the class was changed for correct use in dialogs.
Also, this version of CSPListViewCtrl class supports pages navigation.
The WtlEx library uses this class for internal purposes but you can
use it in your own dialogs or windows.
How to use
First of all, to use this library you need to include WtlEx.rc file in
your resource script. Select "View\Resource Includes:" menu and write
include path to WtlEx.rc file in "Compile-time directives" field
(Example "#include "..\WtlEx\WtlEx.rc"").
CFakeDialogImpl
Usage of this class is very similar to usage of CDialogImpl class,
but you don't need to define a dialog resource identifier
(IDD class member constant) in inherited class. Don't forget to
create your own controls in WM_INITDIALOG handler. The following code
shows how to use CFakeDialogImpl class:
class CFakeDialogDemo : public CFakeDialogImpl<CFakeDialogDemo>
{
public:
//We can set a title for our dialog in CFakeDialogImpl class constructor
CFakeDialogDemo(): CFakeDialogImpl<CFakeDialogDemo>(_T("My Dialog Caption")) {}
BEGIN_MSG_MAP(CFakeDialogDemo)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
RECT rt = {10, 10, 150, 150};
//Create a static control
CStatic wnd;
wnd.Create(*this, &rt, _T("This is demonstration dialog without resources"),
WS_VISIBLE|WS_CHILD|SS_CENTER);
return TRUE;
}
LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
//Close the dialog by IDOK or IDCANCEL commands
EndDialog(wID);
return 0;
}
};
CSPDialogExt
This is a "Mix In" class. To use this class include it in the list
of base classes and chain its message map to the message map of your
class (by CHAIN_MSG_MAP macro - it must be the first entry in the
message map of your class). Example:
class CMyDlg : public CDialogImpl<CMyDlg>,
public CSPDialogExt<CMyDlg>
...
BEGIN_MSG_MAP(CMyDlg)
CHAIN_MSG_MAP(CSPDialogExt<CMyDlg>)
...
END_MSG_MAP()
It is very important to keep in mind that the class intercepts the WM_INITDIALOG message.
Your class will not be able to process this message, instead of this the class CSPDialogExt
will call BOOL OnInitDialog(LPARAM lParam) method. It is recommended to override this
method in your own classes and use it instead of handling WM_INITDIALOG directly. Also
you can not process the WM_COMMAND messages for common IDOK and IDCANCEL
command identifiers. The class automatically processes these messages and calls BOOL
OnOK() method for IDOK and BOOL OnCancel() for IDCANCEL. You can override these
methods to perform additional operations. These methods of CSPDialogExt class simply
close a modal dialog. For example, dialog declaration from the first example, when using
CSPDialogExt class, will look like this:
class CFakeDialogDemo : public CFakeDialogImpl<CFakeDialogDemo>,
public CSPDialogExt<CFakeDialogDemo>
{
public:
CFakeDialogDemo(): CFakeDialogImpl<CFakeDialogDemo>(_T("My Dialog Caption")) {}
typedef CSPDialogExt<CFakeDialogDemo> _baseSPClass;
BEGIN_MSG_MAP(CFakeDialogDemo)
CHAIN_MSG_MAP(_baseSPClass)
END_MSG_MAP()
BOOL OnInitDialog(LPARAM lParam)
{
RECT rt;
CStatic wnd;
GetClientRect(&rt);
wnd.Create(*this, &rt, _T("This is a demonstration dialog without
resources"),
WS_VISIBLE|WS_CHILD|SS_CENTER);
return TRUE;
}
BOOL OnOK()
{
if ( IDYES == MessageBox(_T("Are you sure you want to close the dialog?"),
_T("Fake dialog 2"), MB_YESNO) )
{
//For close a dialog call the base method
_baseSPClass::OnOK();
}
return FALSE;
}
};
Note that we can call GetClientRect from OnInitDialog method,
and that function will return real size of dialog's client area
because CSPDialogExt already positioned the dialog correctly in
its WM_INITDIALOG handler.
By default, CSPDialogExt class performs the following actions:
- Creates normal (m_hDlgFont) and bold (m_hBoldFont) fonts which
you can assign to your controls or use SetFontToAllControls method
to automatically set a new font to all child windows of your dialog.
These fonts are recreated each time WM_SETFONT message is received.
- Removes WS_EX_DLGMODALFRAME style from a dialog window (to create
dialog without border)
- Calls SHInitDialog in WM_INITDIALOG handler before OnInitDialog method
is called (to make the dialog full screen)
- Automatically processes WM_COMMAND messages for the common message
identifiers (IDOK and IDCANCEL)
Besides that, you can pass the following flags to
CSPDailogExt class as a second template parameter:
- FSPDE_STATICBOLD. After a call to OnInitDialog method the class
assigns bold font to all static controls in the dialog. This operation
is also performed when the current font of the dialog is changed (while
processing a WM_SETFONT message).
- FSPDE_HBACK. Removes the default handling of back key (VK_TBACK)
messages from menu bar. Instead, these messages are always redirected
back to control with focus (by using SHSendBackToFocusWindow function).
- FSPDE_HBACKAUTO. This flag is similar to FSPDE_HBACK, but VK_TBACK
key presses are redirected to edit boxes (controls with "edit" or
"capedit" windows class) only. This enables back key to work as a
backspace in edit boxes while preserving common back key functionality.
- FSPDE_SCROLL. Assigns WS_VSCROLL style to dialog.
Here is how these additional styles are used:
class CMyDlg : public CDialogImpl<CMyDlg>,
public CSPDialogExt<CMyDlg, FSPDE_STATICBOLD | FSPDE_HBACKAUTO |
FSPDE_SCROLL>
. . .
typedef CSPDialogExt<CMyDlg, FSPDE_STATICBOLD | FSPDE_HBACKAUTO |
FSPDE_SCROLL> _baseSPClass;
BEGIN_MSG_MAP(CMyDlg)
CHAIN_MSG_MAP(_baseSPClass)
. . .
END_MSG_MAP()
Also, the CSPDialodExt class can create a menu bar from your
resources or one of predefined commonly used menu bars. To make
CSPDialodExt create a menu bar in WM_INITDIALOG handler, add an
IDM constant to your class (you can use enum to create it) and assign
it a resource id of your menu bar, or use one of the following
constants to create a predefined common menu bar:
IDM_INTERNAL_MENU_EMPTY. Create empty menu bar.
IDM_INTERNAL_MENU_DONE. Create menu bar with one "Done" button (IDOK command identifier).
IDM_INTERNAL_MENU_CANCEL. Create menu bar with one "Cancel" button (IDCANCEL command identifier).
IDM_INTERNAL_MENU_DONECANCEL. Create menu bar with two "Done" and "Cancel" buttons.
So, the following code if enough to create
a fully functional Smartphone-style dialog:
class CDemoSPDialog :
public CDialogImpl<CDemoSPDialog>,
public CSPDialogExt<CDemoSPDialog, FSPDE_HBACKAUTO | FSPDE_STATICBOLD>
{
public:
enum {IDD = IDD_MYSIMPLE,
IDM = IDM_INTERNAL_MENU_DONE}; //Use internal "Done" menu bar
typedef CSPDialogExt<CDemoSPDialog, FSPDE_HBACKAUTO | FSPDE_STATICBOLD> _baseSPClass;
BEGIN_MSG_MAP(CDemoSPDialog)
CHAIN_MSG_MAP(_baseSPClass)
END_MSG_MAP()
};
CSPDialogAuto
Using this class is similar to using CSPDialogExt. The only difference
is that this class sets the most commonly used FSPDE_HBACKAUTO and
FSPDE_STATICBOLD flags by default and you don't need to specify them
manually.
CSPSimpleDialog
This class allows you to create a Smartphone-style dialog without
inheriting a new class for it. For example, to create an "About"
dialog you just need to write the following code:
CSPSimpleDialog<IDD_ABOUTBOX, IDM_INTERNAL_MENU_DONE> dlg; //Resource identifiers pass by template parameters
dlg.DoModal();
CSPPropertyPageImpl, CSPSimplePropertyPage and CSPPropertySheet
CSPPropertySheet. This class is used to display a Smartphone-style
property sheet. It stores an array of property pages (each page must
be derived from CSPPropertyPageImpl class) and calls DoModal method
of a page when the user invokes it from the list.
CSPPropertyPageImpl. Using this class is very similar to using
CDialogImpl class. The only difference is that this class can be used
in conjunction with CSPPropertySheet class.
CSPSimplePropertyPage. Similar to CSimpleDialog. Can be used with
CSPPropertySheet to create a property page without inheriting a new
class for it.
Example of using:
//Declare derived property page
class CPropPage1 : public CSPPropertyPageImpl<CPropPage1>,
public CSPDialogExtAuto<CPropPage1, FSPDE_SCROLL>
{
public:
enum { IDD = IDD_PROP1,
IDM = IDM_INTERNAL_MENU_DONE }; //for CSPDialogExt
typedef CSPDialogExtAuto<CPropPage1, FSPDE_SCROLL> _baseSPClass;
BEGIN_MSG_MAP(CPropPage1)
CHAIN_MSG_MAP(_baseSPClass)
END_MSG_MAP()
BOOL OnInitDialog(LPARAM lParam)
{
//Init some controls
CButton(GetDlgItem(IDC_CHECK2)).SetCheck(BST_CHECKED);
CButton(GetDlgItem(IDC_CHECK4)).SetCheck(BST_CHECKED);
SetDlgItemText(IDC_EDIT1, _T("Text for edit"));
return TRUE;
}
};
...
//Create first property page. Use default title from dialog resource
CPropPage1 p1;
//Create second property page without derives. Use another title.
CSPSimplePropertyPage<IDD_ABOUTBOX, IDM_INTERNAL_MENU_DONE> p2(_T("Simple page"));
//Create Property Sheet
CSPPropertySheet sheet(_T("Select some properties"));
//Add pages to property sheet
sheet.AddPage(p1);
sheet.AddPage(p2);
//Run Property Sheet dialog
sheet.DoModal();
Conclusion
First version of WtlEx library contains useful classes for dialog and
property sheet development. Using these classes in your project would allow you
to avoid writing routine code and speed up application development.
Discuss
Discuss this article.
Here you can write your comments and read comments of other developers.
|