Win32 Button在Direct2D窗口中无法正常常驻显示的问题
问题根因
- 控件创建逻辑位置错误:
CreateWindow是一次性的窗口创建接口,你把它放在逐帧执行的渲染函数中,每次渲染都会重复创建新的按钮控件,既造成GDI资源泄漏,也完全打乱了子控件的正常绘制生命周期,绝对不要把窗口创建类接口放在逐帧运行的渲染路径中。 - 绘制层级冲突:Direct2D每次执行
Clear()会清空整个渲染目标的像素,直接覆盖子按钮此前绘制的内容。按钮被点击时会收到独立的重绘消息,在你的Direct2D绘制流程结束后触发自身绘制,所以会临时显示;点击其他区域触发父窗口重绘后,Direct2D的清屏操作再次覆盖按钮区域,按钮就会消失;程序初次启动时没有触发按钮的独立重绘,所以默认看不到。 - 父窗口缺少必要样式:默认情况下父窗口绘制不会裁剪子控件区域,Direct2D的绘制操作会直接写入子控件对应的像素区域,把子控件内容覆盖掉。
修复步骤
- 把按钮创建逻辑移出渲染函数
按钮只需要在父窗口初始化阶段(比如处理WM_CREATE消息时)创建一次即可,创建后保存按钮句柄,不要放在每帧执行的渲染路径里重复创建。参考代码:// WM_CREATE消息处理中执行,仅运行一次 HWND hwndButton = CreateWindow( L"BUTTON", L"a button", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 0, 0, 150, 150, m_hwnd, NULL, (HINSTANCE)GetWindowLongPtr(m_hwnd, GWLP_HINSTANCE), NULL); - 给父窗口添加
WS_CLIPCHILDREN样式
创建父窗口时在样式参数中加入WS_CLIPCHILDREN,这个样式会让父窗口的所有绘制操作自动跳过子控件占据的区域,从根本上避免Direct2D绘制覆盖按钮内容,是性能最高的方案:CreateWindowEx( 0, L"YOUR_WINDOW_CLASS_NAME", L"D2D App", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, // 新增WS_CLIPCHILDREN样式 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL ); - (可选兜底)如果不想修改窗口样式,可以在每次Direct2D绘制结束后主动触发子控件重绘,让子控件在Direct2D内容上层绘制:
m_pRenderTarget->EndDraw(); // 通知所有子控件执行重绘 RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_NOERASE);
完成以上修改后,按钮会在程序启动时正常显示,不会再被Direct2D的绘制操作覆盖。
内容的提问来源于stack exchange,提问作者Pupppy44
相关产品推荐
相关产品推荐

