Firemonkey高DPI窗体切换屏幕后缩放比例不更新求助
解决Firemonkey Per Monitor V2下跨屏幕DPI缩放不更新问题
针对你遇到的Firemonkey窗体切换屏幕后DPI缩放未自动更新的问题,可以通过以下几种方式手动触发DPI感知和缩放刷新:
1. 利用OnScreenChanged事件监听屏幕切换
Firemonkey的TForm自带OnScreenChanged事件,当窗体切换到不同屏幕时会触发。在该事件中手动更新窗体DPI并刷新3D视图:
代码实现:
在窗体头文件声明事件处理函数:
void __fastcall OnFormScreenChanged(TObject *Sender);
在窗体cpp文件绑定事件并实现逻辑:
// 窗体构造时绑定事件 __fastcall TGraphForm::TGraphForm(TComponent* Owner) : TForm(Owner) { this->OnScreenChanged = &OnFormScreenChanged; } void __fastcall TGraphForm::OnFormScreenChanged(TObject *Sender) { // 获取当前窗体所在屏幕的DPI int targetDPI = Screen->Monitors[Screen->MonitorNum]->PixelsPerInch; // 强制更新窗体DPI缩放 this->UpdateDPI(targetDPI); // 刷新TViewPort3D确保3D内容适配新缩放 ViewPort3D1->Invalidate(); }
2. 重写WndProc处理系统DPI变更消息
在Windows平台下,Per Monitor V2模式下系统会向切换屏幕的窗体发送WM_DPICHANGED消息,通过重写窗体的WndProc直接处理该消息:
代码实现:
void __fastcall TGraphForm::WndProc(TMessage &Message) { if (Message.Msg == WM_DPICHANGED) { // 从消息参数中提取新DPI值 int newDPI = HIWORD(Message.WParam); // 更新窗体DPI缩放 this->UpdateDPI(newDPI); // 强制刷新3D视图 ViewPort3D1->Repaint(); } // 调用父类处理其他消息 TForm::WndProc(Message); }
3. 移动窗体时手动触发DPI更新
如果你的窗体是通过代码直接移动到目标屏幕,可以在移动完成后手动发送WM_DPICHANGED消息,确保DPI缩放立即更新:
代码实现:
void MoveGraphFormToTargetScreen(TGraphForm *Form, int TargetMonitorIdx) { if (TargetMonitorIdx < 0 || TargetMonitorIdx >= Screen->MonitorCount) return; TMonitor *targetScreen = Screen->Monitors[TargetMonitorIdx]; // 将窗体移至目标屏幕并设置全屏 Form->BoundsRect = targetScreen->BoundsRect; // 手动发送DPI变更消息触发缩放更新 Form->Perform(WM_DPICHANGED, MAKELPARAM(targetScreen->PixelsPerInch, 0), 0); }
注意事项:
- 确保项目已开启Per Monitor V2 DPI感知(在项目选项的"Application"->"Manifest"中配置)。
- 窗体的
Scaled属性需保持为true,确保Firemonkey处理缩放逻辑。 - 若
TViewPort3D内的3D控件仍有缩放异常,可在DPI更新后调用其ApplyScale方法强制适配。
内容的提问来源于stack exchange,提问作者Barry Andrews
相关产品推荐
相关产品推荐

