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

Direct2D窗口最大化后绘图尺寸变形(正方形变长方形)求助

解决Direct2D窗口最大化后图形拉伸的问题

嘿,这个问题我刚学Direct2D的时候也踩过坑!本质就是窗口客户区的宽高比变化后,你的绘图逻辑没适配新尺寸——Direct2D默认会把绘制的图形直接映射到当前像素空间,原来的小窗口宽高比和最大化后的宽屏(比如16:9)不一样,固定尺寸的正方形自然就被拉成长方形了。

给你两个实用的解决方案,按需选择:

方案一:动态适配窗口尺寸,始终绘制正方形

这个方法会根据当前窗口的实际大小,自动调整正方形的尺寸和位置,保证它永远是正方形,还能居中显示。

  1. 先监听窗口大小变化:在你的窗口过程函数里处理WM_SIZE消息,把当前客户区的宽高存下来,然后触发重绘:

    // 可以用全局变量或者类成员来存客户区尺寸
    float m_clientWidth;
    float m_clientHeight;
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
            case WM_SIZE:
                // 获取当前客户区的宽和高
                m_clientWidth = LOWORD(lParam);
                m_clientHeight = HIWORD(lParam);
                // 告诉窗口需要重绘
                InvalidateRect(hwnd, NULL, FALSE);
                break;
            // 其他消息处理(比如WM_PAINT、WM_DESTROY)...
        }
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    
  2. 在绘制逻辑里动态计算:每次绘制时,根据存下来的宽高,算出正方形的边长(取宽高中的较小值,保证是正方形),再居中绘制:

    HRESULT Render()
    {
        HRESULT hr = S_OK;
    
        pRenderTarget->BeginDraw();
        // 先清空背景为黑色
        pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black));
    
        // 计算正方形边长:留20%的边距,避免贴边
        float squareSize = min(m_clientWidth, m_clientHeight) * 0.8f;
        // 计算居中的坐标
        float posX = (m_clientWidth - squareSize) / 2.0f;
        float posY = (m_clientHeight - squareSize) / 2.0f;
    
        // 绘制白色正方形
        pRenderTarget->FillRectangle(
            D2D1::RectF(posX, posY, posX + squareSize, posY + squareSize),
            pWhiteBrush
        );
    
        hr = pRenderTarget->EndDraw();
        return hr;
    }
    

方案二:用变换矩阵保持图形原始宽高比

如果你希望图形保持最初的大小比例,哪怕窗口拉伸也不变形(就像视频的“保持比例”模式,多余区域显示背景),可以用Direct2D的变换矩阵来实现。

  1. 在WM_SIZE里计算变换矩阵:

    case WM_SIZE:
        m_clientWidth = LOWORD(lParam);
        m_clientHeight = HIWORD(lParam);
        // 这里替换成你初始窗口的宽高(比如你原来的小窗口是800x600)
        float originalWidth = 800.0f;
        float originalHeight = 600.0f;
        float originalRatio = originalWidth / originalHeight;
        float currentRatio = m_clientWidth / m_clientHeight;
    
        D2D1::Matrix3x2F transformMatrix;
    
        if (currentRatio > originalRatio)
        {
            // 当前窗口更宽,按高度缩放,水平方向居中
            float scale = m_clientHeight / originalHeight;
            float offsetX = (m_clientWidth - originalWidth * scale) / 2.0f;
            transformMatrix = D2D1::Matrix3x2F::Translation(offsetX, 0) 
                            * D2D1::Matrix3x2F::Scale(scale, scale);
        }
        else
        {
            // 当前窗口更高,按宽度缩放,垂直方向居中
            float scale = m_clientWidth / originalWidth;
            float offsetY = (m_clientHeight - originalHeight * scale) / 2.0f;
            transformMatrix = D2D1::Matrix3x2F::Translation(0, offsetY) 
                            * D2D1::Matrix3x2F::Scale(scale, scale);
        }
    
        // 把变换矩阵应用到RenderTarget上
        pRenderTarget->SetTransform(transformMatrix);
        InvalidateRect(hwnd, NULL, FALSE);
        break;
    
  2. 绘制时用原始尺寸:这样不管窗口怎么变,你的正方形都会保持最初的比例,不会被拉伸:

    // 用你最初小窗口里绘制的正方形尺寸就行
    pRenderTarget->FillRectangle(
        D2D1::RectF(100.0f, 100.0f, 500.0f, 500.0f),
        pWhiteBrush
    );
    

小提醒

如果你的RenderTarget是ID2D1HwndRenderTarget,窗口大小变化时别忘了调用Resize更新它的尺寸:

pRenderTarget->Resize(D2D1::SizeU((UINT32)m_clientWidth, (UINT32)m_clientHeight));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:03:36