三论在C++类中实现Windows窗口的创建

转载 2007年09月12日 20:34:00

//========================================================================
//TITLE:
//    三论在C++类中实现Windows窗口的创建
//AUTHOR:
//    norains
//DATE:
//    Tuesday  16-January -2007
//Environment:
//  EVC4.0 + Standard SDK
//========================================================================

  关于在C++类中创建windows窗口,之前已经在《在C++类中实现Windows窗口的创建》以及《对<在C++类中实现Windows窗口的创建>一文的补充》这两篇文章中讨论,不过其缺点也是显而易见的:前者对外暴露了一个丑陋的接口,没有真正意义上的完全封装;后者引入了友元机制,使得代码异常复杂,并且还有一个很大的隐患,就是如果定义多个对象,会造成只有最后一个对象实例正常运作.
  
  而本文将要讨论的封装,则是改进以上缺点,令代码更加安全且通俗易懂.
  
  我们以一个已经封装好的窗口类作为例子,首先请看源代码:

        /**///////////////////////////////////////////////////////////////////////
        // DrawWnd.h: interface for the CDrawWnd class.
        /**///////////////////////////////////////////////////////////////////////
        
        #ifndef DRAWWND_H
        
#define DRAWWND_H
        
        
class CDrawWnd  
        
...{
        
        
        
public:
            BOOL ShowWindow(BOOL bShow);
            BOOL Initialize(HINSTANCE hInst);
            
static CDrawWnd * GetInstance();
            
virtual ~CDrawWnd();
        
        
protected:
            
static LRESULT WndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
            
void OnPaint(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
            CDrawWnd();
            
static CDrawWnd *m_pInstance;
        
        }
;
        
        
#endif // !defined DRAWWND_H

 

        /**///////////////////////////////////////////////////////////////////////
        // DrawWnd.cpp: implementation of the CDrawWnd class.
        /**///////////////////////////////////////////////////////////////////////
        
        #include 
"stdafx.h"
        #include 
"DrawWnd.h"
        
        
//-------------------------------------------------------------------
        
//Intialize
        CDrawWnd *CDrawWnd::m_pInstance = NULL;
        
//--------------------------------------------------------------------
        
//Macro define
        #define DRAWWND_CLASS            TEXT("DrawWnd_Class")
        
#define DRAWWND_TITLE            TEXT("DrawWnd_Title")
        
        
//Screen width
        #define SCREEN_WIDTH            GetSystemMetrics(SM_CXSCREEN)
        
//Screen height
        #define SCREEN_HEIGHT            GetSystemMetrics(SM_CYSCREEN)
        
        
/**///////////////////////////////////////////////////////////////////////
        // Construction/Destruction
        /**///////////////////////////////////////////////////////////////////////
        
        CDrawWnd::CDrawWnd()
        
...{
            m_hInst 
= NULL;
            m_hWnd 
= NULL;
        
        }

        
        CDrawWnd::
~CDrawWnd()
        
...{
            delete m_pInstance;
            m_pInstance 
= NULL
        }

        
        
//----------------------------------------------------------------------
        
//Description:
        
//    Get the object instance
        
//--------------------------------------------------------------------
        CDrawWnd * CDrawWnd::GetInstance()
        
...{
            
if(m_pInstance == NULL)
            
...{
                m_pInstance 
= new CDrawWnd();
            }

            
return m_pInstance;
        
        }

        
        
        
        
//----------------------------------------------------------------------
        
//Description:
        
//    The window process
        
//--------------------------------------------------------------------
        LRESULT CDrawWnd::WndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
        
...{
            
switch(wMsg)
            
...{
                
case WM_MOUSEMOVE:
                    m_pInstance
->OnPaint(hWnd,wMsg,wParam,lParam);
                    
return 0;    
            }

            
return DefWindowProc(hWnd,wMsg,wParam,lParam);
        }

        
        
        
        
//----------------------------------------------------------------------
        
//Description:
        
//    Initialize the window
        
//--------------------------------------------------------------------
        BOOL CDrawWnd::Initialize(HINSTANCE hInst)
        
...{
        
            m_hInst 
= hInst;
        
            WNDCLASS wc;
            wc.style
=0;
            wc.lpfnWndProc
=WndProc; 
            wc.cbClsExtra
=0;
            wc.cbWndExtra
=0;
            wc.hInstance
=hInst;
            wc.hIcon
=NULL;
            wc.hCursor
=NULL;
            wc.hbrBackground
=(HBRUSH)GetStockObject(WHITE_BRUSH);
            wc.lpszMenuName
=NULL;
            wc.lpszClassName
=DRAWWND_CLASS;
            
if(RegisterClass(&wc)==0)
            
...{
                
return FALSE;
            }

        
        
            m_hWnd 
= CreateWindow(
                                DRAWWND_CLASS,
                                DRAWWND_TITLE,
                                WS_POPUP ,
                                
0,
                                
0,
                                SCREEN_WIDTH,
                                SCREEN_HEIGHT,
                                NULL,
                                NULL,
                                m_hInst,
                                NULL
                                );
                    
            
if(IsWindow(m_hWnd)==FALSE)
            
...{
                
return FALSE;
            }

        
            
return TRUE;
        }

        
        
//----------------------------------------------------------------------
        
//Description:
        
//    Show the window
        
//--------------------------------------------------------------------
        BOOL CDrawWnd::ShowWindow(BOOL bShow)
        
...{
            
if(m_hWnd == NULL)
            
...{
                
return FALSE;
            }

            
if(bShow == TRUE)
            
...{
                ::ShowWindow(m_hWnd,SW_SHOW);
            }

            
else
            
...{
                ::ShowWindow(m_hWnd,SW_HIDE);
            }

            
return TRUE;
        }

        
        
//----------------------------------------------------------------------
        
//Description:
        
//    Show the window
        
//--------------------------------------------------------------------
        void OnPaint(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
        
...{
            DefWindowProc(hWnd,wMsg,wParam,lParam);
        }

        

  一些具体的设计细节请容许我稍后再谈,现在就让我们来看看怎么让这个类正常运作吧!
  
  由于已经将构造函数声明为protected,所以我们只能申明一个对象指针.等等,也许有人会问,为什么要把构造函数声明为指针?恩,心急的家伙们,这个问题还是暂且搁下,留待稍后再论,现在我们主要任务是还是前面所说的:让类正常运作!
        //声明一个对象指针:
        CDrawWnd *pDrawWnd;
        
        
//获取一个对象实例:
        pDrawWnd = CDrawWnd::GetInstance();
    
        
//初始化窗口:
        if(pDrawWnd->Initialize(hInstance) == FALSE)
        
...{
            
return 0x05;
        }


        
//如果窗口初始化成功,我们就可以让它显示了
        if(pDrawWnd->ShowWindow(TRUE) == FALSE)
        
...{
            
return 0x10;
        }

  恩,对的,就是这么简单,四条语句,就可以让窗口正常显示在我们屏幕上.是不是觉得很轻松呢?恩哈,那就好,希望你还能保持这种愉快的心情的来继续讨论CDrawWnd类的实现细节.
  
  看过我写的《对<在C++类中实现Windows窗口的创建>一文的补充》的朋友,对于现在的这个类应该非常高兴了,没有异常烦琐的友元,也没有声明多个对象导致产生的指针错误,一切都显得那么美好,难道不是么?
  
  CDrawWnd类之所以能正常工作,关键在于声明了一个静态回调函数GetInstance()和一个同样也是静态的对象实例m_pInstance.
  
  GetInstance()主要作用便是返回m_pInstance对象,让该类能起到相应的作用.m_pInstance在我们的类里,也是一个辛勤的员工,因为回调函数WndProc()里对消息的所有操作,都需要m_pInstance亲力而为.在我们上面的示例代码中,我们就可以看到这名辛勤的员工是如何帮助我们处理WM_PAINT消息的:
  m_pInstance->OnPaint(hWnd,wMsg,wParam,lParam);

  虽然最后OnPaint()函数最后也只是很无聊地调用DefWindowProc()完成它的使命,但这毕竟是m_pInstance架起的桥梁,不是么?
  
  当然咯,m_pInstance勤劳归勤劳,但它也是有脾气的:静态的变量,不属于任何对象,只属于类.明白问题的所在了么?也就是说,如果我们定义多个对象,那么m_pInstance永远只指向最后一个定义的对象.嗯哈,由此引发的问题,估计就不是不严重了.
  
  也正是因为这个原因,所以我们只能将功劳巨大的构造函数定义为protected.这样,我们就永远不能直接定义类的对象,也就完全杜绝上文提到的那个非常严重的结果.
  
  现在,如果想要获取类的对象实例,我们就只能通过GetInstance().而在GetInstance()内部,我们当然不会坐以待毙,自然做了相应处理,让其永远只能定义一个类的对象实例.
  
  好了,现在是不是已经豁然开朗,性情舒畅了呢?不过,先别急,再让我们看看一个非常有趣的问题.
  
  如果我们是在EVC4.0或VC6.0下进行调试,试着把下面这条语句屏蔽掉然后再编译:
  CDrawWnd *CDrawWnd::m_pInstance = NULL;

  屏蔽掉了么?是不是很奇怪,编译居然无法通过,并且提示的错误是重复定义了m_pInstance!
  
  我们再来看点更有趣的,尝试着把GetInstance()函数的实现从类外移回类的声明处.我们再编译一次,嗯,看到什么了么?顺利编译通过!
  
  呵呵,C++标准中可没有规定返回静态变量的函数只能在类的声明处进行定义哦.所以嘛,接下来我要说的估计大家也都知道,就不再罗嗦了.
 

Windows,C++编程创建窗口的过程详解

Windows,C++编程,创建窗口的是个步骤详解
  • rl529014
  • rl529014
  • 2015年07月10日 17:31
  • 10016

重温WIN32 API ------ 最简单的Windows窗口封装类

如果你也厌倦了复杂的MFC,这里提供了一个非常简单的把C++类、对象与窗口类、对象联系起来的方式。...
  • smstong
  • smstong
  • 2015年01月04日 17:14
  • 11431

C++Windows编程之创建窗口

Windows编程之注册窗口类介绍了注册窗口类。接下来就是创建窗体。     我们用Visual Studio创建一个win32项目上会自动生成一个创建窗体函数。如下: [cpp]...
  • chenxu6
  • chenxu6
  • 2014年12月24日 19:56
  • 2572

windows程序设计——窗口类

一 创建并显示一个窗口的“遐想”。 ? 首先,要显示的窗口在哪里呢?     要想显示你自己的窗口,显然你得事先创建一个自己的窗口。当你想要一个窗口时,Window系统才会为你创建窗口。不要时,W...
  • misterdo
  • misterdo
  • 2015年05月16日 10:41
  • 2233

非窗口实现定时器的方法

定时器在视窗系统 的程式中的作用不可忽略,也随处可见。设定一个时间间隔每0.5秒或1秒钟刷新一次时钟,这样就能完成一个简单的电子钟程式。在不同的编程工具中定时器的用法也不同,Visual C++中也给...
  • csweier
  • csweier
  • 2016年12月01日 18:35
  • 763

Windows编程-创建窗口

窗口创建的基本步骤是: 设计窗口类 注册窗口类 创建窗口 显示更新窗口 消息循环 编写回调函数——————————帅气的分割线—————————– 下面我们一步一步进行讲解: 1.设计窗口类WNDC...
  • Nick_Wang94
  • Nick_Wang94
  • 2016年08月04日 23:10
  • 1741

C++ Windows对象和MFC对象的区别

看了视频一头雾水,通过网上查阅感觉这篇比较适合新手,我能看懂你就能看懂! windows对象并不是我们平时所说的“面向对象”程序设计中的“类的对象”,而是一种windows资源实体,...
  • chentaowangyuanyuan
  • chentaowangyuanyuan
  • 2015年08月16日 03:27
  • 1428

在windows下用c++编写守护进程

写一个C++程序,监控另一个进程,发现该进程关掉了就自动把它重启  #include   #include   #include   #include   using namespace...
  • u013408061
  • u013408061
  • 2016年11月24日 01:21
  • 1385

简单的C++线程类实现, windows平台

一个抽象的线程基类, 再来个具体的线程类并实现相关接口,再写个主函数来调用下。上代码: Thread.h /* Windows平台线程类实现 开发环境: Win7_x64 + VC2012...
  • JoeBlackzqq
  • JoeBlackzqq
  • 2015年03月06日 15:29
  • 1341

Win32 SDK基础(7)—— 怎样创建一个窗口的子窗口

什么是子窗口?当我们在点击Windows窗口的某个按钮时,比如点击窗口的关闭按钮,往往会弹出一个窗口来提示相关信息,类似这种弹出窗口就是主窗口的子窗口。我们创建子窗口时,也是使用CreateWindo...
  • lzhui1987
  • lzhui1987
  • 2016年12月11日 21:29
  • 3108
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:三论在C++类中实现Windows窗口的创建
举报原因:
原因补充:

(最多只允许输入30个字)