窗口子类化

来源:互联网 发布:淘宝网访问不了 编辑:程序博客网 时间:2024/06/07 02:38

目录:
1、Win32中实现窗口子类化

  • SetWindowSubclass
  • SetWindowLong
  • 示例

2、MFC中实现子类化

  • SubclassDlgItem
  • DDX_Control
  • SubclassWindow

Win32中实现窗口子类化

方法一:
SetWindowSubclass

BOOL SetWindowSubclass(  _In_  HWND hWnd,  _In_  SUBCLASSPROC pfnSubclass,  _In_  UINT_PTR uIdSubclass,  _In_  DWORD_PTR dwRefData);

功能:设置子窗口的回调函数
hWnd:进行子类化的窗口句柄
pfnSubclass:子窗口的回调函数
uIdSubclass:子窗口ID,随便你设置
dwRefData:传递给窗口回调函数的参数,随便你传递
RemoveWindowSubclass

BOOL RemoveWindowSubclass(  _In_  HWND hWnd,  _In_  SUBCLASSPROC pfnSubclass,  _In_  UINT_PTR uIdSubclass);

功能:移除子类化窗口的回调函数
DefSubclassProc

LRESULT DefSubclassProc(  _In_  HWND hWnd,  _In_  UINT uMsg,  _In_  WPARAM WPARAM,  _In_  LPARAM LPARAM);

功能:子类化窗口的默认消息处理函数
GetWindowSubclass

BOOL GetWindowSubclass(  _In_   HWND hWnd,  _In_   SUBCLASSPROC pfnSubclass,  _In_   UINT_PTR uIdSubclass,  _Out_  DWORD_PTR *pdwRefData);

功能:获取子窗口的参数
pdwRefData:输出型参数
回调函数原型

typedef LRESULT ( CALLBACK *SUBCLASSPROC)(  HWND hWnd,  UINT uMsg,  WPARAM wParam,  LPARAM lParam,  UINT_PTR uIdSubclass,  DWORD_PTR dwRefData);

uIdSubclass:这就是SetWindowSubclass第三个参数传递的ID值
dwRefData:这就是SetWindowSubclass第四个参数传递的值


方法二:
SetWindowLong

LONG WINAPI SetWindowLong(  _In_  HWND hWnd,  _In_  int nIndex,  _In_  LONG dwNewLong);

功能:设置子窗口的消息回调函数的新地址,通俗来说就是拦截该空间消息到指定的消息回调函数处理(关于nIndex的参数设置有很多,这里仅使用子类化GWL_WNDPROC参数)
hWnd:进行操作的窗口句柄
nIndex:这里使用 GWL_WNDPROC
dwNewLong:回调函数指针
回调函数原型

LRESULT APIENTRY SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

示例:

#include <windows.h>#include <tchar.h>#include "resource.h"#include <string>using namespace std;#include <Commctrl.h>#pragma comment(lib,"Comctl32.lib")#define SUB_BTN_ID  0x11            HINSTANCE m_hInstance;              // 实例HWND m_hWnd;                        // 主窗口句柄WNDPROC g_EditProc;                 // 回调函数指针enum {    USER_EDIT_CODE = WM_USER + 100, // 自定义消息};INT_PTR CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);                            // 主窗口回调LRESULT CALLBACK BtnSubclassProc(HWND, UINT, WPARAM, LPARAM, UINT_PTR, DWORD_PTR);  // 按钮子类化回调 LRESULT APIENTRY EditSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); // Edit子类化回调int WINAPI _tWinMain(    _In_ HINSTANCE hInstance,    _In_opt_ HINSTANCE hPrevInstance,    _In_ LPTSTR lpCmdLine,    _In_ int nShowCmd){    m_hInstance = hInstance;    DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,DialogProc);    _CrtDumpMemoryLeaks();    return 0;}INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam){    if (uMsg == USER_EDIT_CODE)    {        return true;    }    switch (uMsg)    {    case WM_INITDIALOG:    {        m_hWnd = hwndDlg;        SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_ICON)));        SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_ICON)));        HFONT hFont = CreateFont(-14/*高*/, -7/*宽*/, 0, 0, 700 /*700表示粗体*/,            FALSE/*斜体?*/, FALSE/*下划线?*/, FALSE/*删除线?*/, DEFAULT_CHARSET,            OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,            FF_DONTCARE, TEXT("微软雅黑")        );        SendMessage(GetDlgItem(hwndDlg, IDC_EDIT), WM_SETFONT, (WPARAM)hFont, NULL);        SendMessage(GetDlgItem(hwndDlg, IDC_BTN_TEST), WM_SETFONT, (WPARAM)hFont, NULL);        // SetWindowLong 返回 子类化回调函数进行默认消息处理 的函数指针        g_EditProc = (WNDPROC)SetWindowLong(            GetDlgItem(hwndDlg, IDC_EDIT),  // 进行子类化的窗口句柄            GWL_WNDPROC,                    // 窗口回调(参数)            (LONG)EditSubclassProc);        // 窗口回调函数        if (!SetWindowSubclass(            GetDlgItem(hwndDlg, IDC_BTN_TEST),// 子类化的窗口句柄            BtnSubclassProc,            // 子类化的回调函数            SUB_BTN_ID,             // 被子类化的控件 ID,便于回调函数中判断是哪个窗口的消息            (DWORD_PTR)hwndDlg)     // 传递给子控件的参数            )        {            return FALSE;        }        break;    }    case WM_COMMAND:    {        switch (LOWORD(wParam))        {            case IDCANCEL:            {                RemoveWindowSubclass(GetDlgItem(hwndDlg, IDC_BTN_TEST), BtnSubclassProc, SUB_BTN_ID);                SetWindowLong(GetDlgItem(hwndDlg, IDC_EDIT), GWL_WNDPROC, (LONG)g_EditProc);                EndDialog(hwndDlg, uMsg);                break;             }        }        break;    }    default:        break;    }    return (INT_PTR)FALSE;}LRESULT CALLBACK BtnSubclassProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,    UINT_PTR uIdSubclass,DWORD_PTR dwRefData){    if (uIdSubclass == SUB_BTN_ID)    {        switch (uMsg)        {            case WM_LBUTTONDOWN:            {                wstring txt = _T("这是子类化控件消息");                SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)txt.c_str());                return TRUE;            }        }    }    // 调用窗口的子类链中的下一个处理程序。子类链中的最后一个处理程序调用窗口的原始窗口过程。    return DefSubclassProc(hWnd, uMsg, wParam, lParam);}LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){    switch (uMsg)    {        case WM_RBUTTONDOWN:        {            ::SetWindowText(hwnd, _T("右键点击"));            SendMessage(hwnd, EM_SETSEL, 0, -1);            break;        }        case WM_CHAR:        {            char ascii_code = wParam;            if (ascii_code >= 'A' && ascii_code <= 'Z' || ascii_code >= 'a' && ascii_code <= 'z')            {                SendMessage(m_hWnd, USER_EDIT_CODE, 0, 0);                return true;            }            break;        }    }    return CallWindowProc(g_EditProc, hwnd, uMsg, wParam, lParam);    //return g_EditProc(hwnd, uMsg, wParam, lParam);}

MFC中实现子类化

子类化的实现:我们在一个窗口(指MFC中的窗口,不是其它的界面库)之中,子窗口其实也是接受到消息了的,但是我们却无法处理,此时我们就需要子类化了。子类化其实就是对子窗口(控件也是一个窗口)实现一个消息回调函数(在MFC中就是实现一个消息处理的类,该类实现消息映射),用于处理我们想要的子窗口的消息。
注:MFC中,窗口是覆盖型的,也就是在主窗口的某个区域实现了一个子窗口时,此时该区域接收到消息的是子窗口,而不是主窗口。

方法一
BOOL SubclassDlgItem(UINT nID, CWnd* pParent);
注释:该函数没有子函数,不需要释放
示例:
m_editName.SubclassDlgItem(IDC_NAME, this);

方法二:
DDX_Control宏实现子类化,也就是通过在控件上右键点击,添加关联变量,此时就是通过该宏实现的。实现子类化的一些消息拦截的时候,只需要右键类向导添加自己想要处理的控件消息就行(注:不要添加成主窗口的消息)

方法三:
BOOL SubclassWindow( HWND hWnd );
HWND UnsubclassWindow( );
注释:使用SubclassWindow进行子类化之后,在释放的的时候,要进行UnsubclassWindow反子类化

MSDN示例:

HBRUSH CSuperComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor){   if (nCtlColor == CTLCOLOR_EDIT)   {      //Edit control       if (m_edit.GetSafeHwnd() == NULL)         m_edit.SubclassWindow(pWnd->GetSafeHwnd());   }   else if (nCtlColor == CTLCOLOR_LISTBOX)   {      //ListBox control       if (m_listbox.GetSafeHwnd() == NULL)         m_listbox.SubclassWindow(pWnd->GetSafeHwnd());   }   HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);   return hbr;}void CSuperComboBox::OnDestroy(){   //unsubclass edit and list box before destruction    if (m_edit.GetSafeHwnd() != NULL)      m_edit.UnsubclassWindow();   if (m_listbox.GetSafeHwnd() != NULL)      m_listbox.UnsubclassWindow();   CComboBox::OnDestroy();}

关于控件关联的 Attach Detach 的记录
BOOL Attach( HWND hWndNew );
HWND Detach( );
解释:Attach使得变量与控件相关联,我们通过相关联的变量就可以实现对控件的操作。在退出程序的时候,要进行对关联进行释放(MSDN:分离 CWnd 对象的一个Windows句柄并返回处理)。

m_list.Attach(::GetDlgItem(GetSafeHwnd(), IDC_LIST));m_list.SetBkColor(RGB(220, 255, 255));//深青色 浅青色m_list.SetTextBkColor(RGB(220, 255, 255));m_list.SetTextColor(RGB(0, 0, 255));m_list.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);m_list.InsertColumn(0, _T("工号"), 0, 120);m_list.InsertColumn(1, _T("姓名"), 0, 160);m_list.InsertColumn(2, _T("工资"), 0, 160);m_list.InsertColumn(3, _T("入职日期"), 0, 160);m_list.Detach();

示例代码:https://pan.baidu.com/s/1o7YE0Hk
本文难免有所错误,如有问题欢迎留言

原创粉丝点击