采取ATL实现无模板对话框的显示
添加时间:2013-8-12 点击量:
在采取ATL、WTL的开辟对话框法度的标准办法是从CDialogImpl上持续,然后在类中定义一个IDD,把这个窗口与资料接洽关系起来。若是不定这个IDD是编译不经由过程的,代码如下:
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUTBOX };
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/)
// LRESULT CommandHandler(WORD /wNotifyCode/, WORD /wID/, HWND /hWndCtl/, BOOL& /bHandled/)
// LRESULT NotifyHandler(int /idCtrl/, LPNMHDR /pnmh/, BOOL& /bHandled/)
LRESULT OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/);
LRESULT OnCloseCmd(WORD /wNotifyCode/, WORD wID, HWND /hWndCtl/, BOOL& /bHandled/);
};
在有些景象下,我们并不会采取窗口模板来创建窗口,而是对话框及所有的控件都采取自定义的体式格式来实现,比我们经由过程按照设备文件来生成控件列表。为了实现这个需求我开辟一个无模板对话框类,代码如下:
typedef CWinTraits<WS_POPUP|WS_BORDER|WS_SYSMENU|DS_MODALFRAME|WS_CAPTION,
WS_EX_DLGMODALFRAME | WS_EX_CONTROLPARENT> CDialogWinTraits;
template <class T, class TWinTraits = CDialogWinTraits, class TBase = CWindow>
class ATL_NO_VTABLE CNTDialogImpl : public CDialogImplBaseT< TBase >
{
public:
#ifdef _DEBUG
bool m_bModal;
CNTDialogImpl() : m_bModal(false) { }
#endif //_DEBUG
// modal dialogs
virtual INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), _U_RECT rect = NULL,
LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0)
{
// 创建模板
LPDLGTEMPLATE pTemplate = CreateDlgTemplate (dwStyle, dwExStyle, szWindowName);
if (pTemplate == NULL) return -1;
// 更新地位
if (rect.m_lpRect)
{
pTemplate->x = (short)rect.m_lpRect->left;
pTemplate->y = (short)rect.m_lpRect->right;
pTemplate->cx = (short)(rect.m_lpRect->right - rect.m_lpRect->left);
pTemplate->cy = (short)(rect.m_lpRect->bottom - rect.m_lpRect->top);
}
// 开端显示窗口
ATLASSUME(m_hWnd == NULL);
if (m_thunk.Init(NULL,NULL) == FALSE)
{
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
_AtlWinModule.AddCreateWndData(&m_thunk.cd, this);
#ifdef _DEBUG
m_bModal = true;
#endif //_DEBUG
LRESULT ret = DialogBoxIndirect(_AtlBaseModule.GetResourceInstance(),
pTemplate, hWndParent, T::StartDialogProc);
GlobalFree(pTemplate);
return ret;
}
BOOL EndDialog(int nRetCode)
{
ATLASSERT(::IsWindow(m_hWnd));
#ifdef _DEBUG
ATLASSUME(m_bModal); // must be a modal dialog
#endif //_DEBUG
return ::EndDialog(m_hWnd, nRetCode);
}
protected:
LPWORD lpwAlign ( LPWORD lpIn)
{
ULONG ul = (ULONG) lpIn;
ul +=3; ul >>= 2; ul <<= 2;
return (LPWORD) ul;
}
// 创建对话框模板
LPDLGTEMPLATE CreateDlgTemplate (DWORD dwStyle, DWORD dwExStyle, LPCTSTR szWindowName)
{
HGLOBAL hgbl = NULL;
LPDLGTEMPLATE lpdt = NULL;
LPWORD lpw = NULL;
LPWSTR lpwsz = NULL;
hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl) return NULL;
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
// 定义窗口样式
lpdt->style = TWinTraits::GetWndStyle (dwStyle);
lpdt->dwExtendedStyle = TWinTraits::GetWndExStyle (dwExStyle);
lpdt->cdit = 0; // 窗口中的控件数量
lpdt->x = 0;
lpdt->y = 0;
lpdt->cx = 100; // 默认宽度
lpdt->cy = 50; // 默认高度
lpw = (LPWORD) (lpdt + 1);
lpw++ = 0 x0000; // 没有菜单
lpw++ = 0 x0000; // 采取默认类
lpwsz = (LPWSTR) lpw;
int nchar = 0;
if (szWindowName)
{
int slen = _tcslen(szWindowName) + 1;
_tcsncpy_s (lpwsz, slen, szWindowName, slen);
nchar = slen;
}
lpw += nchar;
GlobalUnlock(hgbl);
return (LPDLGTEMPLATE) hgbl;
}
};
应用办法为把从CDialogImpl上持续改为从CNTDialogImpl中持续就可以,并且不消再定义IDD:
class CAboutDlg : public CNTDialogImpl<CAboutDlg>
{
public:
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/);
LRESULT OnCloseCmd(WORD /wNotifyCode/, WORD wID, HWND /hWndCtl/, BOOL& /bHandled/);
};
在OnInitDialog中你可以创建你想到的控件,同时好加上窗口居中的代码,不然窗口会显示在主窗口的左则,不太都雅。代码如下:
LRESULT CAboutDlg::OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/)
{
CenterWindow(GetParent()); // 窗口居中
ResizeClient (300, 200); // 调剂窗口大小
//在以下窗口控件
//.......
return TRUE;
}
在采取ATL、WTL的开辟对话框法度的标准办法是从CDialogImpl上持续,然后在类中定义一个IDD,把这个窗口与资料接洽关系起来。若是不定这个IDD是编译不经由过程的,代码如下:
class CAboutDlg : public CDialogImpl<CAboutDlg>
{
public:
enum { IDD = IDD_ABOUTBOX };
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/)
// LRESULT CommandHandler(WORD /wNotifyCode/, WORD /wID/, HWND /hWndCtl/, BOOL& /bHandled/)
// LRESULT NotifyHandler(int /idCtrl/, LPNMHDR /pnmh/, BOOL& /bHandled/)
LRESULT OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/);
LRESULT OnCloseCmd(WORD /wNotifyCode/, WORD wID, HWND /hWndCtl/, BOOL& /bHandled/);
};
在有些景象下,我们并不会采取窗口模板来创建窗口,而是对话框及所有的控件都采取自定义的体式格式来实现,比我们经由过程按照设备文件来生成控件列表。为了实现这个需求我开辟一个无模板对话框类,代码如下:
typedef CWinTraits<WS_POPUP|WS_BORDER|WS_SYSMENU|DS_MODALFRAME|WS_CAPTION,
WS_EX_DLGMODALFRAME | WS_EX_CONTROLPARENT> CDialogWinTraits;
template <class T, class TWinTraits = CDialogWinTraits, class TBase = CWindow>
class ATL_NO_VTABLE CNTDialogImpl : public CDialogImplBaseT< TBase >
{
public:
#ifdef _DEBUG
bool m_bModal;
CNTDialogImpl() : m_bModal(false) { }
#endif //_DEBUG
// modal dialogs
virtual INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), _U_RECT rect = NULL,
LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0)
{
// 创建模板
LPDLGTEMPLATE pTemplate = CreateDlgTemplate (dwStyle, dwExStyle, szWindowName);
if (pTemplate == NULL) return -1;
// 更新地位
if (rect.m_lpRect)
{
pTemplate->x = (short)rect.m_lpRect->left;
pTemplate->y = (short)rect.m_lpRect->right;
pTemplate->cx = (short)(rect.m_lpRect->right - rect.m_lpRect->left);
pTemplate->cy = (short)(rect.m_lpRect->bottom - rect.m_lpRect->top);
}
// 开端显示窗口
ATLASSUME(m_hWnd == NULL);
if (m_thunk.Init(NULL,NULL) == FALSE)
{
SetLastError(ERROR_OUTOFMEMORY);
return -1;
}
_AtlWinModule.AddCreateWndData(&m_thunk.cd, this);
#ifdef _DEBUG
m_bModal = true;
#endif //_DEBUG
LRESULT ret = DialogBoxIndirect(_AtlBaseModule.GetResourceInstance(),
pTemplate, hWndParent, T::StartDialogProc);
GlobalFree(pTemplate);
return ret;
}
BOOL EndDialog(int nRetCode)
{
ATLASSERT(::IsWindow(m_hWnd));
#ifdef _DEBUG
ATLASSUME(m_bModal); // must be a modal dialog
#endif //_DEBUG
return ::EndDialog(m_hWnd, nRetCode);
}
protected:
LPWORD lpwAlign ( LPWORD lpIn)
{
ULONG ul = (ULONG) lpIn;
ul +=3; ul >>= 2; ul <<= 2;
return (LPWORD) ul;
}
// 创建对话框模板
LPDLGTEMPLATE CreateDlgTemplate (DWORD dwStyle, DWORD dwExStyle, LPCTSTR szWindowName)
{
HGLOBAL hgbl = NULL;
LPDLGTEMPLATE lpdt = NULL;
LPWORD lpw = NULL;
LPWSTR lpwsz = NULL;
hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl) return NULL;
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
// 定义窗口样式
lpdt->style = TWinTraits::GetWndStyle (dwStyle);
lpdt->dwExtendedStyle = TWinTraits::GetWndExStyle (dwExStyle);
lpdt->cdit = 0; // 窗口中的控件数量
lpdt->x = 0;
lpdt->y = 0;
lpdt->cx = 100; // 默认宽度
lpdt->cy = 50; // 默认高度
lpw = (LPWORD) (lpdt + 1);
lpw++ = 0 x0000; // 没有菜单
lpw++ = 0 x0000; // 采取默认类
lpwsz = (LPWSTR) lpw;
int nchar = 0;
if (szWindowName)
{
int slen = _tcslen(szWindowName) + 1;
_tcsncpy_s (lpwsz, slen, szWindowName, slen);
nchar = slen;
}
lpw += nchar;
GlobalUnlock(hgbl);
return (LPDLGTEMPLATE) hgbl;
}
};
应用办法为把从CDialogImpl上持续改为从CNTDialogImpl中持续就可以,并且不消再定义IDD:
class CAboutDlg : public CNTDialogImpl<CAboutDlg>
{
public:
BEGIN_MSG_MAP(CAboutDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/);
LRESULT OnCloseCmd(WORD /wNotifyCode/, WORD wID, HWND /hWndCtl/, BOOL& /bHandled/);
};
在OnInitDialog中你可以创建你想到的控件,同时好加上窗口居中的代码,不然窗口会显示在主窗口的左则,不太都雅。代码如下:
LRESULT CAboutDlg::OnInitDialog(UINT /uMsg/, WPARAM /wParam/, LPARAM /lParam/, BOOL& /bHandled/)
{
CenterWindow(GetParent()); // 窗口居中
ResizeClient (300, 200); // 调剂窗口大小
//在以下窗口控件
//.......
return TRUE;
}