我的一个 Win32 程序运行时需要大量重绘,但这样会导致它的 Win32 控件闪烁。
此外,我还通过在窗口过程函数中处理 WM_CTLCOLORSTATIC 消息,使我的控件背景透明了:
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255, 0, 0));
return (LRESULT)GetStockObject(NULL_BRUSH); // 控件背景透明
}
为了解决控件闪烁的问题,我已经尝试了在主窗口中启用 WS_CLIPCHILDREN 属性,但是它会导致我的控件背景不再透明。
请问怎样能在窗口大量重绘的情况下,使我的控件不闪烁,而且背景是透明的?
为了说明 WS_CLIPCHILDREN 属性会导致控件背景不再透明,以下附了一份代码。代码中创建了一个窗口和一个透明背景的 Static 控件,但是由于启用了 WS_CLIPCHILDREN 属性,控件背景变得不透明了。(这个代码用的是 main 函数,而不是 WinMain,需要控制台项目编译)
#include <windows.h>
#include <thread>
#define IDC_STATIC 100
//////////// 设置是否启用 WS_CLIPCHILDREN 样式
//////////// 启用时可以避免闪烁,但是控件背景不透明了
bool g_bEnableStyle = true;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance = GetModuleHandle(0);
static HWND hStatic;
switch (msg)
{
case WM_CREATE:
{
hStatic = CreateWindow(
L"static",
L"我是透明控件",
WS_CHILD | WS_VISIBLE,
20, 22, 100, 20,
hwnd,
(HMENU)IDC_STATIC,
hInstance,
NULL
);
hStatic = CreateWindow(
L"button",
L"BTN",
WS_CHILD | WS_VISIBLE,
220, 22, 100, 20,
hwnd,
(HMENU)IDC_STATIC,
hInstance,
NULL
);
break;
}
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255, 0, 0));
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_CLOSE:
DestroyWindow(hwnd);
PostQuitMessage(NULL);
exit(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initwindow(int w, int h, int mode, LRESULT(_stdcall* WindowProcess)(HWND, UINT, WPARAM, LPARAM), LPCTSTR strWndTitle)
{
// 窗口类
WNDCLASSEX WndClassEx;
MSG Msg;
// 隐藏cmd
if (mode == 0)
ShowWindow(GetConsoleWindow(), SW_HIDE);
// 填写结构体
WndClassEx.cbSize = sizeof(WNDCLASSEX);
WndClassEx.style = CS_VREDRAW | CS_HREDRAW;
WndClassEx.lpfnWndProc = WindowProcess;
WndClassEx.cbClsExtra = 0;
WndClassEx.cbWndExtra = 0;
WndClassEx.hInstance = GetModuleHandle(0);
WndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClassEx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WndClassEx.lpszMenuName = NULL;
WndClassEx.lpszClassName = strWndTitle;
WndClassEx.hIconSm = NULL;
// 注册窗口类
RegisterClassEx(&WndClassEx);
// 创建窗口
HWND hWnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
strWndTitle,
strWndTitle,
WS_OVERLAPPEDWINDOW | (g_bEnableStyle ? WS_CLIPCHILDREN : 0),
200, 200, w, h,
NULL,
NULL,
GetModuleHandle(0),
NULL
);
// 显示窗口
ShowWindow(hWnd, SW_SHOWNORMAL);
// 更新窗口
UpdateWindow(hWnd);
clock_t time = clock();
// 循环获得消息
while (GetMessage(&Msg, NULL, NULL, NULL))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
// 模拟大量重绘
if (clock() - time >= 10)
{
InvalidateRect(hWnd, nullptr, true);
time = clock();
}
}
}
int main()
{
initwindow(640, 480, 0, WndProc, L"mywnd");
return 0;
}