大量重绘窗口时,如何避免 Win32 控件闪烁?

ZouHuiDong 2022-12-03 06:52:47

我的一个 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;
}
...全文
130 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
CSDN-Ada助手 2023-01-13
  • 打赏
  • 举报
回复
您可以前往 CSDN问答-编程语言 发布问题, 以便更快地解决您的疑问

399

社区成员

发帖
与我相关
我的任务
社区描述
PowerBuilder 非技术版
社区管理员
  • 非技术版社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧