Mastering the Art of Creating Custom Windows in Your Applications

作者:渭南麻将开发公司 阅读:53 次 发布时间:2023-08-03 15:28:16

摘要:随着应用程序的复杂性越来越高,业务需求也越来越多,如何展现出交互性、视觉效果良好的UI界面是必须要解决的一个问题。其中,窗口的创建是其中非常关键的一个组成部分。在Win32编程中,创建窗口的API是CreateWindow。通过本文,你将掌握自定义窗口的技巧,让你的应用程序变得更加精彩。一、...

随着应用程序的复杂性越来越高,业务需求也越来越多,如何展现出交互性、视觉效果良好的UI界面是必须要解决的一个问题。其中,窗口的创建是其中非常关键的一个组成部分。在Win32编程中,创建窗口的API是CreateWindow。通过本文,你将掌握自定义窗口的技巧,让你的应用程序变得更加精彩。

Mastering the Art of Creating Custom Windows in Your Applications

一、了解CreateWindow函数

CreateWindow函数是Win32编程中的一个API函数,它用于创建一个新的窗口。

WINDPROC CreateWindow(

LPCTSTR lpClassName,

LPCTSTR lpWindowName,

DWORD dwSyle,

int x, int y,

int nWidth, int nHeight,

HWND hWndParent,

HMENU hMenu,

HINSTANCE hInstance,

LPVOID IpParam

);

参数解释:

· lpClassName:窗口类名。可以通过WNDCLASSEX结构体创建一个窗口类。

· lpWindowName:窗口名。可以设置为 NULL 或者字符串指针。

· dwStyle:窗口样式,它包括窗口边框、标题栏和窗口的外观和行为。

· x,y:窗口左上角的坐标。

· nWidth、nHeight:窗口的大小。

· hWndParent:父窗口句柄。可以是其他窗口的句柄,也可以是桌面窗口的句柄。

· hMenu:窗口菜单的句柄。通常设置为 NULL表示没有菜单。

· hInstance:应用程序实例的句柄,使用GetModuleHandle(NULL)获取。

· IpParam:传递给窗口过程的参数。多数情况下,可以设置为NULL。

二、自定义窗口

通过CreateWindow函数创建的窗口具有标准的外观和相应样式,但并不能满足较为复杂的业务需求,因此我们需要自定义窗口。

1. 设置窗口样式

dwStyle参数定义了窗口的行为和外观,利用它可以改变窗口的样式。下面是一些比较常用的样式:

· WS_CAPTION:具有标题栏和窗口边框,按下关闭按钮时将发送WM_CLOSE消息。

· WS_CHILD:指定父窗口的子窗口,它的坐标相对于父窗口的客户区。

· WS_CLIPCHILDREN:指定如果有子窗口,那么当这些子窗口被绘制时,不会将它们绘制到父窗口所在区域。

· WS_DISABLED:指定窗口不能接收输入焦点。

· WS_EX_TOOLWINDOW:指定窗口是工具窗口,其标题栏和窗口边框将远比标准窗口边框更窄。

· WS_THICKFRAME:指定窗口有大小调整和三个标准的标题栏按钮。(最小化、最大化、关闭)

2. 创建窗口类

在 Win32 程序中,窗口不是通过直接调用 CreateWindow 函数进行创建,而是首先需要定义一个窗口类,再调用 CreateWindowEx 函数来创建。

下面是创建窗口类的步骤:

· 创建WNDCLASSEX结构体实例,该结构体用于定义窗口类的属性

WNDCLASSEX wndClass = {};

wndClass.cbSize = sizeof(WNDCLASSEX);

wndClass.style = CS_HREDRAW | CS_VREDRAW;

wndClass.lpfnWndProc = WndProc;

wndClass.hInstance = hInstance;

wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wndClass.lpszClassName = L"MainWndClass";

注意,WNDCLASSEX结构体中必须指定 lpfnWndProc 成员,它指向窗口过程的地址。

· 注册窗口类

如果窗口类的成员 lpfnWndProc 未被设置,此时 RegisterClassEx 将调用失败。如果 lpfnWndProc 成员已被设置,则 RegisterClassEx 成功注册窗口类。

if (!RegisterClassEx(&wndClass))

{

MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_OK);

return 1;

}

· 创建并显示窗口

接下来,我们便可以使用 CreateWindowEx 函数创建窗口并进行显示:

hwnd = CreateWindowEx(0,

L"MainWndClass",

L"自定义窗口",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL);

三、绘制自定义窗口

除了定义窗口的样式外,它的外观也需要做一个定制,这里我们通过处理 WM_PAINT 消息为例,实现窗口绘制。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

switch (message)

{

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hWnd, &ps);

//TODO: 绘制代码

EndPaint(hWnd, &ps);

}

break;

case WM_CLOSE:

DestroyWindow(hWnd);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

在 WM_PAINT 消息中,通过 BeginPaint 函数获取客户区的设备上下文(HDC),接着我们就可以在该上下文中绘制了,绘制完成后再通过 EndPaint 函数结束绘制。

四、自定义边框与标题栏

对于窗口的标题栏和边框,约定俗成的做法是使用一个带有标题栏和边框的容器窗口。而对于方案两,我们一般使用 DWM(Desktop Windows Manager)来完成。

1. DWM 的使用

DWM 是 Vista 以及以后版本中引入的新特性。在 Windows 7 中,DWM 可以让我们做到脱离 GDI+ 使用 WPF 一样的 Vista 平台的扩展颜色和渐变效果。

DWM 的核心 API 是 DwmExtendFrameIntoClientArea 和 DwmEnableBlurBehindWindow。它们可以让我们实现一些高级特效。

2. 使用DWM实现自定义窗口

首先,需要在窗口类中注册 DWM 发送的消息:

case WM_DWMCOMPOSITIONCHANGED:

//当函数来自桌面组合时,警告DWM正在进行广泛修改

DwmIsCompositionEnabled(&bGlass);

InvalidateRect(hwnd, NULL, FALSE);

return 0;

这里,我们可以获取 DWM 是否可用,并在 ValidateRect 函数中向 Windows 更新整个窗口:

DwmExtendFrameIntoClientArea(hwnd, &margins);

UpdateWindow(hwnd);

最后就是在 WM_PAINT 消息中使用 DWM 绘制窗口:

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

HRESULT hr = S_OK;

if (bGlass)

{

RECT rcClient;

GetClientRect(hwnd, &rcClient);

hr = pDwmExtendFrameIntoClientArea(hdc, &margins);

if (FAILED(hr))

{

DeleteDC(hdc);

EndPaint(hwnd, &ps);

return 0;

}

FillRect(hdc, &rcClient, (HBRUSH)COLOR_WINDOW);

DrawText(hdc, L"Hello World!", -1, &rcClient,

DT_CENTER | DT_VCENTER | DT_SINGLELINE);

}

else

{

RECT rcWindow;

GetWindowRect(hwnd, &rcWindow);

int cx = rcWindow.right - rcWindow.left;

int cy = rcWindow.bottom - rcWindow.top;

int w = cx - 2 * BORDER;

int h = cy - CAPTION - BORDER;

FillRect(hdc, &ps.rcPaint, (HBRUSH)COLOR_WINDOW);

DrawCaption(hwnd, hdc, &ps.rcPaint, DC_SMALL|DC_ICON|DC_TEXT|DC_INBUTTON);

HRGN hrgnInside = CreateRectRgn(BORDER, CAPTION, w + BORDER, h + CAPTION);

SelectClipRgn(hdc, hrgnInside);

DeleteObject(hrgnInside);

HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));

RECT rBorder = { BORDER, CAPTION, w + BORDER, h + CAPTION };

FrameRect(hdc, &rBorder, hBrush);

}

EndPaint(hwnd, &ps);

}

break;

这里,我们使用了 DrawCaption 函数绘制标题栏,然后使用 CreateRectRgn 函数创建客户区域内的矩形区域,调用 SelectClipRgn 函数进行剪切,最后在该区域内绘制边框即可。

五、总结

本文向你展示了如何使用 CreateWindow 函数创建窗口,以及如何自定义窗口的样式和外观。通过学习窗口面向的知识,你可以对窗口进行自由控制和更自由的美化,有助于提升应用的可用性。

  • 原标题:Mastering the Art of Creating Custom Windows in Your Applications

  • 本文链接:https:////zxzx/244961.html

  • 本文由深圳飞扬众网小编,整理排版发布,转载请注明出处。部分文章图片来源于网络,如有侵权,请与飞扬众网联系删除。
  • 微信二维码

    CTAPP999

    长按复制微信号,添加好友

    微信联系

    在线咨询

    点击这里给我发消息QQ客服专员


    点击这里给我发消息电话客服专员


    在线咨询

    免费通话


    24h咨询☎️:166-2096-5058


    🔺🔺 棋牌游戏开发24H咨询电话 🔺🔺

    免费通话
    返回顶部