Delphi不同屏幕分辨率下硬编码坐标自动缩放适配问题咨询
问题原因
你遇到的缩放差异本质是DPI感知配置不同导致的:
- 旧版Delphi 10编译出的程序默认未声明高DPI感知,Windows会在高DPI设备上对程序窗口做系统级位图拉伸,硬编码的固定坐标会跟着拉伸,看起来比例正常,但这种缩放会导致界面文字、图形模糊。
- Delphi 10.4 Community Edition默认开启了Per Monitor V2 高DPI感知,此时系统不再做自动位图拉伸,所有传入画布、控件API的坐标默认按当前显示器物理像素计算,裸写的固定像素值不会随DPI缩放;而
ClientWidth、ClientHeight这类属性本身是VCL框架经过DPI换算后的值,所以可以正常适配缩放。
无需批量修改硬编码坐标的解决方法
方法1:调整项目DPI配置(零代码修改,和旧程序表现完全一致)
如果不需要高DPI下的清晰显示效果,直接把项目DPI感知模式改成和旧Delphi一致即可,操作步骤:
- 打开项目后依次进入
Project -> Options -> Application -> Manifest - 在DPI Awareness下拉菜单中选择
Unaware,重新编译后程序就会和你旧笔记本编译的版本完全一样,由Windows自动完成缩放,不需要改任何代码。
注意:该方案的缺点是高DPI下界面会存在系统拉伸带来的模糊感。
方法2:使用VCL内置缩放方法(保留高DPI清晰度,最小化代码修改)
Delphi 10.4的VCL框架内置了DPI缩放的辅助方法,不需要手动计算缩放比,只需要对硬编码的96DPI设计值做一层简单包裹即可:
所有你在96DPI下写的固定像素坐标、尺寸值,用窗体/控件自带的ScaleValue方法包裹,框架会自动根据当前设备DPI换算成正确的物理像素值。
针对你给出的绘图代码,修改示例如下:
procedure TForm1.Button1Click(Sender: TObject); begin with Canvas do begin MoveTo(0,0); // 对96DPI下的硬编码值做缩放转换 LineTo(ScaleValue(400), ScaleValue(250)); MoveTo(0,0); LineTo(ClientWidth,ClientHeight); end; end;
如果代码里硬编码值非常多,不想逐处修改,可以直接把窗体的Scaled属性保持为默认开启的True,在项目源码(一般是.dpr文件的begin块)里加一行Application.MainFormOnTaskBar := True; 之后设置全局Screen.PixelsPerInch := 96;,VCL会自动对所有运行期的坐标、尺寸做全局缩放,效果比系统位图缩放更清晰,不需要逐行改业务代码。
长期适配建议
后续开发时尽量避免裸写固定像素值,优先用相对尺寸(比如基于ClientWidth、ClientHeight的比例值),或者统一用逻辑坐标(96DPI为基准)配合LogicalToPhysicalPoint、PhysicalToLogicalPoint方法做转换,就不需要反复适配不同DPI的设备。
内容的提问来源于stack exchange,提问作者Rudi
相关产品推荐
相关产品推荐

