c++ - 如何正确绘制简单的非客户区(4 px 红色边框)?
问题描述
我正在尝试绘制自定义绘制的非客户区域,而不是默认主题边框(Windows 10)。
我处理WM_NCCALCSIZE
将非客户区的大小调整为每侧 4 个像素,然后处理WM_NCPAINT
绘制红色边框。
我的自定义绘画在首次显示应用程序时成功,但在调整应用程序大小或最小化和恢复时无法重绘,尽管在调整大小或恢复窗口时两者都被调用WM_NCCALCSIZE
。WM_NCPAINT
#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "window";
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(
WS_EX_COMPOSITED,
"window",
NULL,
WS_OVERLAPPEDWINDOW,
100,
100,
600,
400,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
SetWindowTheme(hWnd, L"", L"");
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCCALCSIZE:
{
RECT rect;
GetWindowRect(hWnd, &rect);
LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
ncParams->rgrc[0].top = rect.top + 4;
ncParams->rgrc[0].left = rect.left + 4;
ncParams->rgrc[0].bottom = rect.bottom - 4;
ncParams->rgrc[0].right = rect.right - 4;
return 0;
}
case WM_NCPAINT:
{
RECT rect;
GetWindowRect(hWnd, &rect);
HDC dc = GetDCEx(hWnd, (HRGN) wParam, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
HGDIOBJ old = SelectObject(dc, pen);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Rectangle(dc, 0, 0, width, height);
SelectObject(dc, old);
DeleteObject(pen);
ReleaseDC(hWnd, dc);
return 0;
}
case WM_NCACTIVATE:
RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
return 0;
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
解决方案
wParam
of消息有时会返回 1而WM_NCPAINT
不是区域句柄 ( HRGN
)。在这种情况下HRGN
必须使用CreateRectRgn
函数创建。
#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "window";
wcex.hIconSm = NULL;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(
NULL,
"window",
NULL,
WS_OVERLAPPEDWINDOW,
100,
100,
600,
400,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
SetWindowTheme(hWnd, L"", L"");
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCCALCSIZE:
{
LPNCCALCSIZE_PARAMS ncParams = (LPNCCALCSIZE_PARAMS) lParam;
ncParams->rgrc[0].top += 4;
ncParams->rgrc[0].left += 4;
ncParams->rgrc[0].bottom -= 4;
ncParams->rgrc[0].right -= 4;
return 0;
}
case WM_NCPAINT:
{
RECT rect;
GetWindowRect(hWnd, &rect);
HRGN region = NULL;
if (wParam == NULLREGION) {
region = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
} else {
HRGN copy = CreateRectRgn(0, 0, 0, 0);
if (CombineRgn(copy, (HRGN) wParam, NULL, RGN_COPY)) {
region = copy;
} else {
DeleteObject(copy);
}
}
HDC dc = GetDCEx(hWnd, region, DCX_WINDOW | DCX_CACHE | DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
if (!dc && region) {
DeleteObject(region);
}
HPEN pen = CreatePen(PS_INSIDEFRAME, 4, RGB(255, 0, 0));
HGDIOBJ old = SelectObject(dc, pen);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Rectangle(dc, 0, 0, width, height);
SelectObject(dc, old);
ReleaseDC(hWnd, dc);
DeleteObject(pen);
return 0;
}
case WM_NCACTIVATE:
RedrawWindow(hWnd, NULL, NULL, RDW_UPDATENOW);
return 0;
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
推荐阅读
- jsf - 是否可以从后台进程访问 JSF ApplicationScoped bean?
- go - 位桶管道中的 Go mod dep 错误
- php - 本地 wordpress 安装的 Frontity Api 连接问题
- r - R中的`webshot`抛出“我是`fs`模块幻影错误:TypeError:未定义不是构造函数”
- javascript - 为 javascript 视频播放器解析 m3u8
- python - 计算并减去不是今天的日期的特定时间
- javascript - 从 API 解析后更改值
- list - Tkinter 组合框再次循环。得到结果
- python - 尝试根据用户输入在网格中制作多个动态字计数器
- node.js - docker-entrypoint.sh:在 $PATH 中找不到可执行文件