Introduction
Numeric input on the Pocket PC has always been a hassle. The numeric keyboard provided by the SIP is too small and not directly accessible. Plus, it's always nice to be able to perform some calculations before entering data.
With these issues in mind, I developed the numeric key pad dialog to help entering numeric data in Pocket PC applications.
Implementation
The sample application I include in this article implements the numeric key pad using two different approaches: window controls and windowless controls.
The first approach uses regular Windows controls such as buttons and static labels to draw the keypad. Instead of a static dialog resource that can be found in regular applications, all controls are created from a dynamically created dialog resource. The class CDialogTemplate
(see sample project) is based on FlipCode's Dialog Template code by Max McGuire.
The second approach (depicted on the picture above) doesn't use window controls, but objects that derive from CSubWnd
. These objects live on a CSubWndContainer
that is an MFC's CWnd
and is responsible for dispatching all incoming (and relevant) Windows messages to the contained CSubWnd
objects. Each CSubWnd
-derived object is responsible for painting its own rectangle and processing clicks. Here's how CSubWndContainer
dispatches the paint requests:
void CSubWndContainer::OnPaint()
{
CPaintDC dc(this);
CSubWndCont::iterator pos,
end = m_cont.end();
HFONT hFontOld;
hFontOld = (HFONT)::SelectObject(dc, m_hFont);
for(pos = m_cont.begin(); pos != end; ++pos)
if(dc.RectVisible(&(*pos)->GetRect()))
(*pos)->Paint(dc);
::SelectObject(dc, hFontOld);
}
To make click handling easier (and to reduce the number of virtual functions), all click-related Windows messages are dispatched to a single CSubWnd
function:
void CSubWndContainer::OnLButtonDown(UINT nFlags, CPoint point)
{
m_pSubWnd = SubWndFromPoint(point);
if(m_pSubWnd)
m_pSubWnd->Click(CLICK_DOWN, point);
}
void CSubWndContainer::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_pSubWnd)
m_pSubWnd->Click(CLICK_UP, point);
}
void CSubWndContainer::OnLButtonDblClk(UINT nFlags, CPoint point)
{
m_pSubWnd = SubWndFromPoint(point);
if(m_pSubWnd)
m_pSubWnd->Click(CLICK_DOWN | CLICK_DOUBLE, point);
}
The sample code uses two CSubWnd
-derived classes: CSubStatic
used to implement the topmost static control and CSubButton
that implements all the keypad buttons. Note how this class has to work around the Windows built-in double-click processing:
void CSubButton::Click(DWORD dwClick, POINT pt)
{
bool bOn = (dwClick & CLICK_DOWN);
ASSERT(m_pWnd);
if(dwClick & CLICK_DOUBLE)
Click(CLICK_UP, pt);
if(m_rc.PtInRect(pt))
{
if(IsActive() && !bOn)
{
CWnd* pParent = m_pWnd->GetParent();
if(pParent)
pParent->SendMessage(WM_COMMAND, m_nID,
(LPARAM)m_pWnd->GetSafeHwnd());
}
Activate(bOn);
}
else
{
if(IsActive())
Activate(false);
}
}
The numeric keypad implementation is quite straightforward. The value being edited is always a double
that can be converted to an int
or a CURRENCY
. It is displayed in a format that the client chooses:
enum Format
{
fmtInteger, fmtNumber, fmtCurrency };
To consume this class, create an instance of CNumPadDlg
using the appropriate constructor arguments:
CNumPadDlg(enum Format format, BOOL bTemplate, CWnd* pParent = NULL);
Before calling the object's DoModal
function, set the keypad value using one of:
void SetIntValue(int nVal);
void SetDblValue(double dblVal);
void SetCurValue(CURRENCY cyVal);
Retrieve the keypad value using the corresponding get function:
int GetIntValue();
double GetDblValue();
CURRENCY GetCurValue();
And that's it!
Final Notes
This code uses Giuseppe Govi's STL implementation. It's a bit minimal but sufficient for most Pocket PC applications (and is compatible with eVC3).