You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Direct2D平移变换随鼠标移动时出现意外偏移问题

Direct2D平移时图形偏离鼠标位置的问题修复

问题现象

按住鼠标中键拖动时,图形随鼠标移动,但移动距离越远,图形偏离鼠标的程度越明显。尝试过GET_X_LPARAM、GetCursorPos()+ScreenToClient计算偏移,以及调整渲染目标尺寸,均未解决。

问题根源

  1. DPI缩放不匹配:窗口创建时做了DPI缩放,但鼠标坐标是客户端像素,而Direct2D渲染目标使用设备无关单位(DIP),两者未做转换,导致偏移量计算错误。
  2. 平移逻辑方向错误:Direct2D的Translation变换是将坐标系向指定方向移动,要让图形跟随鼠标拖动,偏移量应取鼠标移动量的反方向,否则会出现“越拖越远”的偏移。
  3. 偏移量类型错误:pan_offset定义为整数类型POINT,但Direct2D变换需要浮点精度,累积整数误差会导致偏移越来越大。
  4. 初始位置记录逻辑缺陷:WM_MOUSEMOVE中用静态变量记录鼠标位置,可能出现初始化异常,导致初始偏移计算错误。

修复步骤

  1. 将pan_offset改为浮点类型D2D1_POINT_2F,避免整数累积误差。
  2. 增加DPI转换逻辑,将鼠标像素坐标转为Direct2D使用的DIP单位。
  3. 调整平移方向,让渲染目标坐标系向鼠标移动的反方向偏移。
  4. 在WM_MBUTTONDOWN事件中记录初始鼠标位置和当前偏移量,保证拖动逻辑的准确性。

修改后的关键代码

头文件修改

class DemoApp
{
public:
    // ... 原有成员 ...
private:
    // ... 原有成员 ...
    static D2D1_POINT_2F pan_offset;
    D2D1_POINT_2F lastPanMousePos;  // 按下中键时的鼠标DIP位置
    D2D1_POINT_2F lastPanOffset;    // 按下中键时的当前偏移
};

源文件修改

  1. 初始化静态成员
D2D1_POINT_2F DemoApp::pan_offset = D2D1::Point2F(0, 0);
  1. 完善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))
{}
  1. 新增鼠标中键按下/抬起消息处理
// 在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;
}
  1. 修正鼠标移动时的偏移计算
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;
}
  1. 修正平移变换方向
void DemoApp::UpdateTransform()
{
    // 取反偏移量,让图形跟随鼠标拖动方向移动
    D2D1_MATRIX_3X2_F transform =
        D2D1::Matrix3x2F::Translation(-pan_offset.x, -pan_offset.y);
    m_pRenderTarget->SetTransform(transform);
}

内容的提问来源于stack exchange,提问作者user25472896

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:48:10