Direct2D平移变换随鼠标移动时出现意外偏移问题
Direct2D平移时图形偏离鼠标位置的问题修复
问题现象
按住鼠标中键拖动时,图形随鼠标移动,但移动距离越远,图形偏离鼠标的程度越明显。尝试过GET_X_LPARAM、GetCursorPos()+ScreenToClient计算偏移,以及调整渲染目标尺寸,均未解决。
问题根源
- DPI缩放不匹配:窗口创建时做了DPI缩放,但鼠标坐标是客户端像素,而Direct2D渲染目标使用设备无关单位(DIP),两者未做转换,导致偏移量计算错误。
- 平移逻辑方向错误:Direct2D的
Translation变换是将坐标系向指定方向移动,要让图形跟随鼠标拖动,偏移量应取鼠标移动量的反方向,否则会出现“越拖越远”的偏移。 - 偏移量类型错误:
pan_offset定义为整数类型POINT,但Direct2D变换需要浮点精度,累积整数误差会导致偏移越来越大。 - 初始位置记录逻辑缺陷:
WM_MOUSEMOVE中用静态变量记录鼠标位置,可能出现初始化异常,导致初始偏移计算错误。
修复步骤
- 将
pan_offset改为浮点类型D2D1_POINT_2F,避免整数累积误差。 - 增加DPI转换逻辑,将鼠标像素坐标转为Direct2D使用的DIP单位。
- 调整平移方向,让渲染目标坐标系向鼠标移动的反方向偏移。
- 在
WM_MBUTTONDOWN事件中记录初始鼠标位置和当前偏移量,保证拖动逻辑的准确性。
修改后的关键代码
头文件修改
class DemoApp { public: // ... 原有成员 ... private: // ... 原有成员 ... static D2D1_POINT_2F pan_offset; D2D1_POINT_2F lastPanMousePos; // 按下中键时的鼠标DIP位置 D2D1_POINT_2F lastPanOffset; // 按下中键时的当前偏移 };
源文件修改
- 初始化静态成员
D2D1_POINT_2F DemoApp::pan_offset = D2D1::Point2F(0, 0);
- 完善DemoApp构造函数
DemoApp::DemoApp() : m_hwnd(NULL), m_pDirect2dFactory(NULL), m_pRenderTarget(NULL), m_pLightSlateGrayBrush(NULL), m_pCornflowerBlueBrush(NULL), lastPanMousePos(D2D1::Point2F(0,0)), lastPanOffset(D2D1::Point2F(0,0)) {}
- 新增鼠标中键按下/抬起消息处理
// 在WndProc的switch分支中添加 case WM_MBUTTONDOWN: { SetCapture(hwnd); POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; float dpiScale = GetDpiForWindow(hwnd) / 96.0f; // 转换鼠标坐标为DIP单位并记录 pDemoApp->lastPanMousePos = D2D1::Point2F( mousePos.x / dpiScale, mousePos.y / dpiScale ); pDemoApp->lastPanOffset = pan_offset; result = 0; wasHandled = true; break; } case WM_MBUTTONUP: { ReleaseCapture(); result = 0; wasHandled = true; break; }
- 修正鼠标移动时的偏移计算
case WM_MOUSEMOVE: { if (wParam & MK_MBUTTON) { POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; float dpiScale = GetDpiForWindow(hwnd) / 96.0f; D2D1_POINT_2F currentMouseDip = D2D1::Point2F( mousePos.x / dpiScale, mousePos.y / dpiScale ); // 基于初始位置计算当前偏移 pan_offset.x = pDemoApp->lastPanOffset.x + (currentMouseDip.x - pDemoApp->lastPanMousePos.x); pan_offset.y = pDemoApp->lastPanOffset.y + (currentMouseDip.y - pDemoApp->lastPanMousePos.y); pDemoApp->UpdateTransform(); InvalidateRect(hwnd, NULL, FALSE); } result = 0; wasHandled = true; break; }
- 修正平移变换方向
void DemoApp::UpdateTransform() { // 取反偏移量,让图形跟随鼠标拖动方向移动 D2D1_MATRIX_3X2_F transform = D2D1::Matrix3x2F::Translation(-pan_offset.x, -pan_offset.y); m_pRenderTarget->SetTransform(transform); }
内容的提问来源于stack exchange,提问作者user25472896
相关产品推荐
相关产品推荐

