MFC中自定义窗口类名
2018-09-06 11:26
MFC中封装很多常用的控件,把类名也给封装了,没有提供明显的接口出来,用win api写窗口程序,第一步就是注册窗口类
此时类名和标题名是一起注册的,所以能把标题很好地让用户来设定,类名也应该是很简单的,可惜的是MFC没有这样做,原因也许是window name可以不停的改,而类名不能。窗口的类名是有Create来确定的,要在Create前,给窗口选择一个已经注册的窗口类名,作为参数窗口Create就ok了,CWnd的Create最终还是到了CreateEx中来,看看CreateEx就会清楚许多
可以看到最后到了::AfxCtxCreateWindowEx,可以很容易地知道这里调用了CreateWindowEx来创建一个窗口
在前面有一个PreCreateWindow(cs),而cs经过PreCreateWindow处理后,交给::AfxCtxCreateWindowEx处理
::AfxCtxCreateWindowEx在中转给CreateWindowEx,cs.lpszClass就是类名,可以清楚了AfxCtxCreateWindowEx的用心良苦
我们可以重载的PreCreateWindow,来修改类名,如下的代码:
// TODO: 在此添加专用代码和/或调用基类 //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); WNDCLASS wndcls; memset(wndcls, 0, sizeof(WNDCLASS)); // start with NULL // defaults wndcls.style = CS_DBLCLKS CS_HREDRAW CS_VREDRAW; //you can specify your own window procedure wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle(); wndcls.hIcon = NULL; // or load a different icon wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; // Specify your own class name for using FindWindow later wndcls.lpszClassName = _T(MyNewClass); // Register the new class and exit if it fails if(!AfxRegisterClass(wndcls)) { TRACE(Class Registration Failed ); return FALSE; } cs.lpszClass = wndcls.lpszClassName; return TRUE; //return CWnd::PreCreateWindow(cs);
其实就是为了把一个已经注册的类名字符串传给CreateWindowEx,从上面代码中的注释中来看,我还用了一种让系统来生成className的方法AfxRegisterWndClass。CWnd::PreCreateWindow不符合我的心意,注释掉了,其实里面也没什么就是判断而已。而在MFC中CWnd其他派生类就不这么简单了,不过单纯的修改类名,就重载这个方法大多就ok了。
是的,只是大多数可以的,可惜的是这个方法,对于Dialog来说并不行,因为它不用CWnd::Create,也就绕不到
PreCreateWindow上来了,你可以重载对话框的这个方法,断点,是断不下来的。因为CDialog的创建可以直接用系统的api来搞,不用再劳驾CWnd来中转到CReateWindowEx了,所以就不能够用上述方法来改对话框的类名了。
看下它的创建代码了:
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){ ASSERT(IS_INTRESOURCE(lpszTemplateName) AfxIsValidString(lpszTemplateName)); m_lpszTemplateName = lpszTemplateName; // used for help if (IS_INTRESOURCE(m_lpszTemplateName) m_nIDHelp == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // invalid dialog template name PostNcDestroy(); // cleanup if Create fails too soon return FALSE; }#endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); HGLOBAL hTemplate = LoadResource(hInst, hResource); BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hInst); FreeResource(hTemplate); return bResult;}
可以看出来CDialog是靠资源来创建的,可以这样来来搞的,在资源脚本中定义Class “对话框类名”在对话框domodal或者Create前注册这个类名,然后等着modal和Create后就可以了。