windows窗口子类化图解

windows中的static控件的背景色不好改变,因为一般的做法是依赖他的父窗口来给他传入背景画刷才能实现,也就是说需要依赖父窗口。这种方式在duilib中会导致主窗口逻辑会混入子窗口的逻辑,控件也不能复用。

windows提供了一种机制,子类化窗口。可以实现对窗口的功能进行扩展。

参考资料:https://docs.microsoft.com/en-us/windows/win32/controls/subclassing-overview

总结来说子类化窗口是对窗口消息的重定向。

先来看下正常的窗口消息的处理过程。

windows窗口子类化图解

 

 

消息循环把消息队列中的消息取出来后,派发到不同的窗口,各个窗口都有自己的窗口过程,用来处理派发过来的消息。

如果我们需要定制我们特有的功能,就需要能自己处理这些消息,完成定制的逻辑。这个就可以通过子类化窗口来实现。

下面来看下子类化窗口之后的窗口消息处理过程。

 

 

windows窗口子类化图解

 

 

 

 

消息循环把窗口B的消息派发给窗口B后,消息并没有直接交给窗口B的窗口过程,而是交给了我们自定义的窗口过程,在这里,我们可以做我们想做的事情,来实现定制的功能。

然后根据需要是再次调用原来的窗口过程(Case 1),还是认为消息已经处理完毕了(Case 2)。

 

 

子类化窗口API

目前有两种方式来实现:

使用SetWindowLong设置新的窗口过程。

使用SetWindowSubclass来设置子类化窗口过程。

 

 
(1)使用SetWindowLong设置新的窗口过程
  1. 创建窗口CreateWindowExW

  2. 通过SetWindowLong设置新的窗口过程

  3. 在窗口过程中处理自己感兴趣的消息

 

    WNDPROC OldProc = NULL;

    HWND hwnd = ::CreateWindowExW(dwStyleEx, L"Static", NULL, dwStyle, left, top, width, height,

        hParentWnd, NULL, hInstance, NULL);

    OldProc = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)StaticControlProc);

 

    LRESULT CALLBACK StaticControlProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

    {

        if (msg == WM_PAINT)

        {

            PAINTSTRUCT ps = { 0 };

            HDC hdc = BeginPaint(hWnd, &ps);


            RECT rect;

            ::GetClientRect(hWnd, &rect);

            DWORD dwColor = RGB(255, 0, 0);

            HBRUSH hBrush = ::CreateSolidBrush(dwColor);

            HPEN hPen = ::CreatePen(PS_SOLID, 1, dwColor);

            HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hBrush);

            HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);


            ::Rectangle(hdc, 0, 0, rect.right, rect.bottom);


            ::SelectObject(hdc, hOldBrush);

            ::SelectObject(hdc, hOldPen);

            ::DeleteObject(hBrush);

            ::DeleteObject(hPen);


            EndPaint(hWnd, &ps);

            return 0;

        }

        else

        {

            return ::CallWindowProc(OldProc, hWnd, msg, wParam, lParam);

        }

    }


 
(2)使用SetWindowSubclass来设置子类化窗口过程


  1. 创建窗口CreateWindowExW

  2. 通过SetWindowSubclass设置新的窗口过程

  3. 在窗口过程中处理自己感兴趣的消息

 

    HWND hwnd = ::CreateWindowExW(dwStyleEx, L"Static", NULL, dwStyle, left, top, width, height,

        hParentWnd, NULL, hInstance, NULL);

SetWindowSubclass(hwnd, StaticControlProc, 0, 0);

LRESULT CALLBACK StaticControlProc(HWND hWnd, UINT uMsg, WPARAM wParam,

LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)

{

if (uMsg == WM_PAINT)

{

                    // ...

return 0;

}

else

{

return DefSubclassProc(hWnd, uMsg, wParam, lParam);

}

}

 

 

参考资料:

https://www.cnblogs.com/kekec/p/3210696.html

https://blog.csdn.net/bjbz_cxy/article/details/80762692

windows窗口子类化图解

上一篇:C#实现对DropDowList添加下拉选项的方法


下一篇:dataGridView导出为CSV文件