如何创建带标题栏可拖拽缩放的中心镂空窗口?
中心镂空录屏窗口的拖拽与缩放功能实现
我的目标是创建一个类似录屏捕获窗口的中心镂空Window。

我已通过以下代码实现初步效果:
#include <windows.h> LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // 创建四个细长的矩形作为边框 HRGN hRgn1 = CreateRectRgn(0, 0, 10, 300); // 左边框 HRGN hRgn2 = CreateRectRgn(390, 0, 400, 300); // 右边框 HRGN hRgn3 = CreateRectRgn(0, 0, 400, 10); // 上边框 HRGN hRgn4 = CreateRectRgn(0, 290, 400, 300); // 下边框 // 创建空的区域 HRGN hEmptyRgn = CreateRectRgn(10, 10, 390, 290); // 中间区域 // 组合区域 HRGN hCombinedRgn = CreateRectRgn(0, 0, 0, 0); CombineRgn(hCombinedRgn, hRgn1, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgn2, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgn3, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgn4, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hEmptyRgn, hCombinedRgn, RGN_DIFF); // 从组合区域中减去中心区域 // 设置窗口区域 SetWindowRgn(hwnd, hCombinedRgn); // 清理资源 DeleteObject(hRgn1); DeleteObject(hRgn2); DeleteObject(hRgn3); DeleteObject(hRgn4); DeleteObject(hEmptyRgn); DeleteObject(hCombinedRgn); EndPaint(hwnd, &ps); return 0; } default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } void CreateHollowWindow() { const char CLASS_NAME[] = "HollowWindow"; WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = CLASS_NAME; wc.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClass(&wc); HWND hwnd = CreateWindowEx( WS_EX_LAYERED | WS_EX_TOOLWINDOW, CLASS_NAME, "Hollow Window with Borders", WS_POPUP | WS_CAPTION | WS_BORDER, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, GetModuleHandle(NULL), NULL ); // 通过不绘制任何内容使中间镂空 UpdateWindow(hwnd); ShowWindow(hwnd, SW_SHOW); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } int main() { CreateHollowWindow(); return 0; }

当前窗口无标题栏,无法通过拖拽边框进行缩放。请问如何实现正常窗口/对话框的这些功能,仅保留中心镂空?
解决方案
要保留窗口的标题栏拖拽、边框缩放功能,同时维持中心镂空效果,需从窗口样式、区域更新时机、消息处理三个方面调整:
调整窗口创建参数
- 移除
WS_EX_LAYERED扩展样式,它会干扰标准窗口交互;保留WS_EX_TOOLWINDOW避免在任务栏显示。 - 窗口主样式改用
WS_OVERLAPPEDWINDOW,它自带标题栏、边框、缩放按钮及拖拽缩放功能,替代原有的WS_POPUP | WS_CAPTION | WS_BORDER。
- 移除
修改窗口区域设置时机
- 不在
WM_PAINT中重复设置窗口区域(会导致闪烁),改为在窗口创建完成(WM_CREATE)和窗口尺寸变化(WM_SIZE)时更新区域,确保镂空区域随窗口动态调整。
- 不在
动态响应窗口缩放
- 监听
WM_SIZE消息,实时重新计算并设置窗口区域,保证边框宽度固定,中心镂空区域随窗口大小同步变化。
- 监听
调整后的完整代码:
#include <windows.h> #define BORDER_WIDTH 10 // 计算并设置窗口镂空区域 void UpdateHollowRegion(HWND hwnd) { RECT windowRect; GetClientRect(hwnd, &windowRect); int width = windowRect.right - windowRect.left; int height = windowRect.bottom - windowRect.top; // 创建四个边框区域 HRGN hRgnLeft = CreateRectRgn(0, 0, BORDER_WIDTH, height); HRGN hRgnRight = CreateRectRgn(width - BORDER_WIDTH, 0, width, height); HRGN hRgnTop = CreateRectRgn(BORDER_WIDTH, 0, width - BORDER_WIDTH, BORDER_WIDTH); HRGN hRgnBottom = CreateRectRgn(BORDER_WIDTH, height - BORDER_WIDTH, width - BORDER_WIDTH, height); // 合并边框区域 HRGN hCombinedRgn = CreateRectRgn(0, 0, 0, 0); CombineRgn(hCombinedRgn, hRgnLeft, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgnRight, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgnTop, hCombinedRgn, RGN_OR); CombineRgn(hCombinedRgn, hRgnBottom, hCombinedRgn, RGN_OR); // 设置窗口区域并清理资源 SetWindowRgn(hwnd, hCombinedRgn, TRUE); DeleteObject(hRgnLeft); DeleteObject(hRgnRight); DeleteObject(hRgnTop); DeleteObject(hRgnBottom); DeleteObject(hCombinedRgn); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: // 窗口创建完成后初始化镂空区域 UpdateHollowRegion(hwnd); return 0; case WM_SIZE: // 窗口大小改变时更新镂空区域 UpdateHollowRegion(hwnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } void CreateHollowWindow() { const char CLASS_NAME[] = "HollowWindow"; WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = CLASS_NAME; wc.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClass(&wc); HWND hwnd = CreateWindowEx( WS_EX_TOOLWINDOW, // 移除WS_EX_LAYERED,保留工具窗口属性 CLASS_NAME, "Hollow Window with Borders", WS_OVERLAPPEDWINDOW, // 使用标准可缩放窗口样式 CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, GetModuleHandle(NULL), NULL ); ShowWindow(hwnd, SW_SHOW); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } int main() { CreateHollowWindow(); return 0; }
关键说明
- 窗口样式:
WS_OVERLAPPEDWINDOW自带标题栏拖拽、边框缩放功能,无需额外编写拖拽逻辑。 - 区域更新:在
WM_CREATE和WM_SIZE时机设置区域,避免重复创建资源导致的性能问题和界面闪烁。 - 边框控制:通过宏
BORDER_WIDTH统一管理边框粗细,方便后续调整。
内容的提问来源于stack exchange,提问作者Administrator
相关产品推荐
相关产品推荐

