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

如何让窗体上绘制的图形不受显示器分辨率/缩放比例变化影响

高DPI缩放环境下多边形绘制偏移问题解决方案

问题背景

基于Jimi的多边形绘制方案开发的WinForms应用,在1920x1200分辨率、100%缩放的设备上显示正常,但切换到2160x1440(推测输入笔误)、150%缩放的设备时,图形的大小和位置出现明显偏移。


解决思路与步骤

一、项目环境设置调整

  • 启用每显示器DPI感知:
    打开VS2022项目属性→应用程序→窗口设置,将DPI感知设置为每显示器高DPI感知(Per Monitor v2)。
    也可以直接修改app.manifest文件,添加以下配置:
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
      <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
        <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
      </windowsSettings>
    </application>
    
  • 禁用窗体自动缩放:
    在窗体属性中,将AutoScaleMode设置为None,避免WinForms自带的缩放逻辑干扰自定义绘制。

二、代码适配修改

核心是针对当前显示器的DPI缩放系数,对所有绘制参数(坐标、半径、画笔宽度)进行比例转换,确保在不同缩放比例下显示效果一致。修改后的完整代码如下:

Public Class Form1
    ' 基础参数(基于96DPI/100%缩放设计)
    Private ReadOnly baseCenter As PointF = New PointF(200, 100)
    Private ReadOnly baseRadius As Single = 70
    Private ReadOnly basePenWidth As Single = 2
    Dim numberOfSides As Integer = 0
    Const skew As Single = Math.PI * 1.5F ' 修正旋转角度

    ' 当前显示器的DPI缩放系数
    Private currentDpiScaleX As Single = 1.0F
    Private currentDpiScaleY As Single = 1.0F

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        ' 初始化DPI缩放系数
        Using g As Graphics = Me.CreateGraphics()
            currentDpiScaleX = g.DpiX / 96.0F
            currentDpiScaleY = g.DpiY / 96.0F
        End Using
        ' 禁用自动缩放
        Me.AutoScaleMode = AutoScaleMode.None
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        If numberOfSides < 3 Then Return

        ' 计算缩放后的绘制参数
        Dim scaledCenter As PointF = New PointF(baseCenter.X * currentDpiScaleX, baseCenter.Y * currentDpiScaleY)
        Dim scaledRadius As Single = baseRadius * currentDpiScaleX
        Dim scaledPenWidth As Single = basePenWidth * currentDpiScaleX

        Dim polygon = CreatePolygon(scaledRadius, numberOfSides, scaledCenter)

        Using blackPen As New Pen(Color.Black, scaledPenWidth)
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            e.Graphics.DrawPolygon(blackPen, polygon)
        End Using
    End Sub

    Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
        numberOfSides = CInt(ListBox1.SelectedItem)
        Me.Invalidate()
    End Sub

    Public Function CreatePolygon(radius As Single, sides As Integer, center As PointF) As PointF()
        Dim polygon = New PointF(sides - 1) {}
        Dim angle As Single = 360.0F / sides * CSng(Math.PI / 180.0F)

        For side As Integer = 0 To sides - 1
            polygon(side) = New PointF(
            CSng(center.X + radius * Math.Cos(skew + side * angle)),
            CSng(center.Y + radius * Math.Sin(skew + side * angle)))
        Next
        Return polygon
    End Function

    ' 处理跨显示器DPI变化事件
    Protected Overrides Sub OnDpiChanged(e As DpiChangedEventArgs)
        MyBase.OnDpiChanged(e)
        currentDpiScaleX = e.DpiNew.X / 96.0F
        currentDpiScaleY = e.DpiNew.Y / 96.0F
        Me.Invalidate()
    End Sub
End Class

关键修改说明

  • DPI缩放系数计算:以标准96DPI为基准,获取当前显示器的实际DPI值计算缩放比例,保证所有绘制元素按比例放大/缩小。
  • 监听DPI变化:当窗体在不同DPI的显示器间切换时,自动更新缩放系数并刷新绘制,保证显示一致性。
  • 禁用自动缩放:完全接管绘制逻辑,避免WinForms自动缩放导致的偏移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 10:54:50