Introduction
One WTL template I use in many projects is the excellent CDialogResize<T>
. Deriving your dialog class from this template allows you to implement a resizing dialog box very easily indeed. However, one feature it lacks is the ability to persist the dialog size, and this where my small extension class comes in.
CDialogResizeEx<T>
allows the size of the dialog to be stored in the Windows registry at a location of your choice, ensuring that the next time the dialog is displayed, it uses the previous size.
This article doesn't cover the WTL CDialogResize
class - for an excellent explanation on how this works, refer to Michael Dunn's article:
Using WTL's Built-in Dialog Resizing Class
Using CDialogResizeEx
To use this template with an existing CDialogResize derived class, take the following steps:
- Derive from
CDialogResizeEx
instead of CDialogResize
.
- Alter the
CHAIN_MSG_MAP
call to use CDialogResizeEx
.
- In your WM_INITDIALOG handler call
DlgResize_InitEx
instead of DlgResize_Init
.
- Call to the
LoadSize
method to specify the root registry parent and key name where the dialog size will be loaded/saved.
For example, you may have a dialog class that looks like this:
class CMyDialog :
public CDialogImpl<CAnotherDialog>,
public CDialogResizeEx<CAnotherDialog>
{
public:
enum { IDD = IDD_MYDIALOG };
BEGIN_DLGRESIZE_MAP(CMyDialog)
...
END_DLGRESIZE_MAP()
BEGIN_MSG_MAP(CMyDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
...
CHAIN_MSG_MAP(CDialogResizeEx<CMyDialog>)
END_MSG_MAP()
LRESULT OnInitDialog(UINT , WPARAM , LPARAM ,
BOOL& )
{
DlgResize_InitEx();
CenterWindow();
return TRUE;
}
};
Next, to display the dialog you might have the following code:
CMyDialog dlg;
dlg.LoadSize(HKEY_CURRENT_USER, _T("Software\\CodeProject\\DialogResizeEx"));
dlg.DoModal();
That's pretty much it - should only take a few minutes to implement.
Registry Entries
The class will save the dialog size to the registry using the following value names:
dialog_nnn_cx
dialog_nnn_cy
Where nnn is your dialog ID. This allows you to store the size for as many dialogs in your application as you'd like.
Note that if you don't want to store these values in the registry, you can simple set the m_size
member prior to displaying the dialog. When the dialog is closed, m_size
will contain the new dialog size. For example:
CMyDialog dlg;
dlg.m_size.cx = 640;
dlg.m_size.cy = 480;
dlg.DoModal();
CDialogResizeEx
Here is the class:
#pragma once
template <class T>
class CDialogResizeEx : public CDialogResize<T>
{
public:
CSize m_size;
HKEY m_hKeyParent;
LPCTSTR m_lpszKeyName;
CDialogResizeEx(void)
: m_size(0, 0)
, m_hKeyParent(NULL)
, m_lpszKeyName(NULL)
{
};
void DlgResize_InitEx(bool bAddGripper = true, bool bUseMinTrackSize = true,
DWORD dwForceStyle = WS_CLIPCHILDREN)
{
DlgResize_Init(bAddGripper, bUseMinTrackSize, dwForceStyle);
T* pT = static_cast<T*>(this);
if (m_size.cx != 0 && m_size.cy != 0)
{
pT->SetWindowPos(NULL, 0, 0, m_size.cx, m_size.cy,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
CRect rectClient;
pT->GetClientRect(&rectClient);
DlgResize_UpdateLayout(rectClient.Width(), rectClient.Height());
}
}
void LoadSize(HKEY hKeyParent, LPCTSTR lpszKeyName)
{
m_hKeyParent = hKeyParent;
m_lpszKeyName = lpszKeyName;
ATL::CRegKey reg;
if (reg.Open(hKeyParent, lpszKeyName, KEY_READ) == ERROR_SUCCESS)
{
DWORD dw;
#if (_ATL_VER >= 0x0700)
if (reg.QueryDWORDValue(FormatWidthValueName(), dw) == ERROR_SUCCESS)
m_size.cx = dw;
if (reg.QueryDWORDValue(FormatHeightValueName(), dw) == ERROR_SUCCESS)
m_size.cy = dw;
#else
if (reg.QueryValue(dw, FormatWidthValueName()) == ERROR_SUCCESS)
m_size.cx = dw;
if (reg.QueryValue(dw, FormatHeightValueName()) == ERROR_SUCCESS)
m_size.cy = dw;
#endif
}
}
void SaveSize(HKEY hKeyParent, LPCTSTR lpszKeyName) const
{
ATL::CRegKey reg;
if (reg.Create(hKeyParent, lpszKeyName) == ERROR_SUCCESS)
{
#if (_ATL_VER >= 0x0700)
reg.SetDWORDValue(FormatWidthValueName(), m_size.cx);
reg.SetDWORDValue(FormatHeightValueName(), m_size.cy);
#else
reg.SetValue(m_size.cx, FormatWidthValueName());
reg.SetValue(m_size.cy, FormatHeightValueName());
#endif
}
}
CString FormatWidthValueName(void) const
{
const T* pT = static_cast<const T*>(this);
CString strValueName;
strValueName.Format(_T("dialog_%d_cx"), pT->IDD);
return strValueName;
}
CString FormatHeightValueName(void) const
{
const T* pT = static_cast<const T*>(this);
CString strValueName;
strValueName.Format(_T("dialog_%d_cy"), pT->IDD);
return strValueName;
}
BEGIN_MSG_MAP(CDialogResizeEx)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
CHAIN_MSG_MAP(CDialogResize<T>)
END_MSG_MAP()
LRESULT OnDestroy(UINT , WPARAM , LPARAM ,
BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
CRect rect;
pT->GetWindowRect(rect);
m_size.cx = rect.Width();
m_size.cy = rect.Height();
if (m_hKeyParent != NULL && m_lpszKeyName != NULL)
SaveSize(m_hKeyParent, m_lpszKeyName);
bHandled = FALSE;
return 0;
}
};