前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows窗口类

Windows窗口类

作者头像
欧阳大哥2013
发布2018-10-25 15:00:36
1.3K0
发布2018-10-25 15:00:36
举报

Windows编程中,对所有的GUI组件和控件进行了分类,每种类型的实例对象都具有不同的特性,这些特性包括UI外观以及事件的处理和响应的方法。就和面向对象技术中的类和实例对象一样,Windows中也提供了窗口类和窗口实例的概念,在创建一个窗口对象是必须要指定对应的窗口类名称,所有的窗口类必须要先注册到系统中才能进行实例化创建。系统内部默认注册了一些窗口类,比如按钮,编辑框这些窗口类等等。本文所要介绍的就是那些针对窗口类进行操作的API。一个窗口类其实就是定义了这种窗口实例的外观显示的样式、光标在窗口上移动时的样式、以及图标样式、背景绘制的画刷的类型、菜单、以及对应的UI事件处理函数等等。为了唯一的表征一个窗口类,还需要为窗口类指定一个唯一的字符串名称。下面的结构体就是用来描述一个窗口类所应该具有的数据结构:

代码语言:javascript
复制
typedef struct _WNDCLASS { 
  UINT       style;          //窗口显示的样式                                                      
  WNDPROC    lpfnWndProc;   //窗口事件处理函数            
  int        cbClsExtra;                            //窗口类的附加数据尺寸
  int        cbWndExtra;                          //窗口实例对象的附加数据尺寸
  HINSTANCE  hInstance;                   //窗口类所属的应用句柄 
  HICON      hIcon;                               //窗口的图标
  HCURSOR    hCursor;                      //窗口的光标
  HBRUSH     hbrBackground;           //窗口的背景刷
  LPCTSTR    lpszMenuName;          //窗口的菜单
  LPCTSTR    lpszClassName;          //窗口的类名字符串
} WNDCLASS, *PWNDCLASS; 

你还可以使用WNDCLASSEX结构来指定一个窗口类更多的信息。
  • 窗口类的注册 在建立一个窗口类的窗口实例对象前,要先注册这个窗口类,这可以通过调用如下函数来完成。
代码语言:javascript
复制
ATOM RegisterClass(
  CONST WNDCLASS *lpWndClass  // class data
);

ATOM RegisterClassEx(
  CONST WNDCLASSEX *lpwcx  // class data
);

函数的参数就是执行的窗口类数据结构WNDCLASS或者WNDCLASSEX。这两个函数的返回一个原子标识值,用来表示注册的这个窗口类的唯一标识值。

  • 窗口类的反注册 如果不再需要某个窗口类了,就可以调用反注册函数:
代码语言:javascript
复制
BOOL UnregisterClass(
  LPCTSTR lpClassName,  // 窗口类的类名
  HINSTANCE hInstance   // 应用程序句柄
);
  • 窗口类信息的获取 你也可以在窗口类被注册完成后通过如下的函数来进行窗口类信息的获取:
代码语言:javascript
复制
BOOL GetClassInfo(
            HINSTANCE hInstance,    //[IN]应用程序句柄通常为NULL
            LPCTSTR lpClassName,    //[IN]窗口类的类名
            LPWNDCLASS lpWndClass   //[OUT]窗口类的信息为WNDCLASS结构
            );

BOOL GetClassInfoEx(
             HINSTANCE hinst,    // handle to application instance
             LPCTSTR lpszClass,  // class name
             LPWNDCLASSEX lpwcx  // class data
            );
  • 窗口的创建 当注册完一个窗口类后,就可以使用窗口类对应的ClassName来创建这个窗口类下的窗口实例了。
代码语言:javascript
复制
HWND CreateWindow(
LPCTSTR lpClassName,   //RegisterClass方法注册的窗口类或者系统默认的窗口类字符串。
LPCTSTR lpWindowName,  //窗口名称
DWORD dwStyle,  //窗口的样式
int x,  //位置
int y,
int nWidth, //尺寸
int nHeight,
HWND hWndParent,  //所属的父窗口
HMENU hMenu,  //关联的菜单
HANDLE hlnstance,  //应用程序句柄
LPVOID lpParam     //附加参数。
)
  • 从窗口中获取所属的窗口类的名称
代码语言:javascript
复制
int GetClassName(
          HWND hWnd,           //[IN]窗口句柄
          LPTSTR lpClassName,  //[OUT]窗口的类名
          int nMaxCount        //[IN]类名的长度
        );
  • 从窗口中获取所属的窗口类的信息 我们可以通过GetClassName来获取一个窗口所属的窗口类的类名,还可以根据窗口类的类名通过GetClassInfo函数类获取窗口类的所有信息。当然系统还提供了一个直接从窗口获取所属类信息的方法:
代码语言:javascript
复制
DWORD GetClassLong(
               HWND hWnd,  //窗口句柄
               int nIndex  // 欲获得信息的表识
               );

ULONG_PTR GetClassLongPtr(
  HWND hWnd,  // handle to window
  int nIndex  // offset of value to retrieve
);

上面函数中的索引nIndex可以为如下列表中的任意一个:

代码语言:javascript
复制
GCW_ATOM 窗口类的唯一标识(原子),由函数 RegisterClassEx 函数返回
GCL_CBCLSEXTRA 窗口类的扩展信息
GCL_CBWNDEXTRA 窗口的扩展信息 
GCL_HBRBACKGROUND 窗口的背景画刷 
GCL_HCURSOR 窗口的鼠标指针句柄
GCL_HICON 窗口的图标句柄
GCL_HICONSM 窗口最小化时的图标句柄
GCL_HMODULE 应用程序句柄
GCL_MENUNAME 窗口菜单句柄 
GCL_STYLE 窗口类的式样(不是窗口的式样)
GCL_WNDPROC 窗口的回调函数

除了可以获取一个窗口所属的窗口类的信息外,对于一些信息还可以进行设置和改变, 这就可以通过如下函数来操作:

代码语言:javascript
复制
DWORD SetClassLong(
  HWND hWnd,       // handle to window
  int nIndex,      // index of value to change
  LONG dwNewLong   // new value
);

ULONG_PTR SetClassLongPtr(
  HWND hWnd,           // handle to window
  int nIndex,          // index of value to change
  LONG_PTR dwNewLong   // new value
);

需要注意的是并不是所有窗口类属性都可以被改变,而且这个改变只是改变这个窗口中的窗口类信息,并不会影响其他窗口对象的窗口类信息的数据,那么这种改变的作用在哪里呢?这就是下面要提到的窗口子类化的概念。

窗口子类化

我们知道任何一个窗口实例,都是某个窗口类下的实例,而每个窗口类在注册时就指定了窗口实例被创建时的一些特性,比如窗口事件处理回调函数,比如窗口的背景刷句柄等等。。 所有同类型窗口类下的窗口实例对象的这些机制都是一致的。但是在实际中有可能会想要解决窗口类下的某个特定的窗口实例需要具有不同的处理逻辑,尤其是事件处理回调函数。关于这些某些窗口需要进行特定处理的机制就称为窗口的子类化,对于窗口子类化最多的需求就是特化某个窗口的事件处理逻辑,也就是需要修改某个窗口的事件处理回调函数。为了解决这个问题,系统为窗口对象提供了一个SetClassLong/SetClassLongPtr函数来进行窗口类信息的修改机制。就如要修改某个窗口的事件处理回调函数时,我们可以用如下代码来实现:

代码语言:javascript
复制
long CALLBACK WndProcFn(HWND hWnd,UINT uID,WPARAM wParam,LPARAM lParam)
{
    //特定于某个窗口的事件处理逻辑。
}

//执行下面的设置,只有hWnd窗口是使用WndProcFn方法,其他默认的同类型的窗口实例则使用默认的事件处理函数。
SetClassLongPtr(hWnd, GCL_WNDPROC, WndProcFn);

在MFC中我们大量的用到了子类化相关的技术,以及当我们想修改系统默认的控件的事件处理逻辑时就可以借助子类化技术来实现。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.10.17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 窗口子类化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档