每一个MFC应用程序都有一个CWinApp派生类的对象。这个对象对应着程序的主线程。而 CWinApp 类中有一个 CWnd * m_pMainWnd 成员变量。这个成员变量记录了应用程序的主窗口。当你新建一个MFC应用程序的时候,在 InitInstance 函数里都会出现对 m_pMainWnd 赋值的语句,拿基于对话框的应用程序来说,其中的代码为:
CMyDialog dlg; m_pMainWnd=&dlg;
唯一的例外是单文档界面的MFC应用程序,你无法在 InitInstance 函数里看到这段代码,因为它已经被隐藏在 ProcessShellCommand 这个函数里了。由此你就可以下结论了:只要创建自己的窗口类,并将这个类的对象赋值给 m_pMainWnd 成员函数就可以实现自定义的应用程序主窗口。下面的程序将演示如何创建风格怪异的应用程序窗口。如图:
MFC向导是个非常有用的工具,但似乎在微软看来,应用程序的界面就只有对话框,单文档和多文档这么几种。我们有时希望做出风格怪异的窗口,虽然通过修改MFC自动生成的程序也可以做到这一点,但是这往往需要了解MFC里许多非常神秘的参数,而且修改后的代码往往臃肿,而且容易出现匪夷所思的错误。我们要编写干净清爽的代码,所以DIY是最好的方法。
我们最好不要完全不理MFC向导,它确实还是一个好工具。我们可以首先用MFC向导生成一个基于对话框的应用程序。在这个应用程序的基础上进行修改。
在生成了一个基于对话框的应用程序,假设工程名为MyWnd以后,将MyWndDlg.h 和MyWndDlg.cpp这两个文件从工程中删除,你甚至还可以把它们从硬盘上彻底删掉。因为这两个类包含的是应用程序主窗口类,我们已经不再需要它了。同时还应该删去资源文件中的对话框模板。
到了这一步,我们就做好了所有的准备工作,下面开始动手。
用MFC向导向应用程序添加一个MFC类,基类应该选成CWnd。假设这个类的名字是CMyWnd。单击确定以后,可以看见MFC向导已经为你生成了它的构造和析构函数。
每一个CWnd类对应了一个窗口,但创建CWnd及其派生类的一个对象并不能创建一个窗口。(注意:不要把窗口类的对象和操作系统中的窗口对象混淆,窗口类对象只是CWnd 及其派生类的对象,而窗口对象就是桌面上活蹦乱跳的窗口)你需要在一定的时候创建窗口对象,并把它们和你的窗口类对象关联起来。所以,我们在CMyWindow类中添加一个Create成员函数,用以创建这个窗口对象:
BOOL CMyWindow::Create() { constchar * strClassName; //创建背景画刷 m_BrushBGround.CreateSolidBrush(RGB(0,0,0)); //注册窗口类 strClassName=::AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW, ::LoadCursor(NULL,IDC_ARROW),(HBRUSH)m_BrushBGround.GetSafeHandle(), NULL); if(!strClassName) { // TRACE("strClassName is null "); return FALSE; } //设置窗口的位置和大小 CRect RectCreate; RectCreate.top=0; RectCreate.left=0; RectCreate.bottom=200; RectCreate.right=200; //创建窗口对象,注意:Create 函数只能用于创建子窗口,对于应用程序的主窗口,必须使用 //CreateEx函数。 if(!CreateEx(NULL,strClassName,NULL,WS_POPUP|WS_CLIPCHILDREN, RectCreate,(CWnd *)pParent,NULL,NULL)) { return FALSE; } return TRUE; }
完成了这个函数以后,窗口类的框架就基本完成了。现在要做的就是修改Initinstance 函数。首先在CMyWndApp类里添加一个CMyWindow 类的成员变量m_MainWnd,这样在theApp对象被创建的时候,这个成员变量也就被创建了。当然有人倾向于使用new来创建窗口对象,但我个人认为可以不使用new的时候就尽量不要使用它。修改后的Initinstance函数变成:
BOOL CMyWndApp::InitInstance() { // 如果一个运行在 Windows XP 上的应用程序清单指定要 // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, //则需要 InitCommonControls()。否则,将无法创建窗口。 InitCommonControls(); CWinApp::InitInstance(); AfxEnableControlContainer(); m_pMainWnd = &m_MainWnd; if(m_MainWnd.Create()) { //窗口创建成功,开始消息循环; return TRUE; } else { MessageBox(NULL,"内存不够,主窗口创建失败","错误",MB_OK); return FALSE; } }
我在这里使用的是VC.Net,其注释都是中文的。在修改了若干BUG以后,你就可以编译这个程序并开始运行了。运行的结果是一个长宽都为200,顶点在屏幕左上角的黑色窗口,没有标题栏,没有边框,整个就是屏幕上的一个大黑洞。如何?振奋人心吧,用MFC向导从来没有做过这样的怪窗口。