I am with all versions updated: Delphi 10.4.1 and RB 20.04
My monitor is 4K with Windows Zoom at 300%. If I drag the preview window to another monitor Full HD with zoom at 150%, everything is ok on this other monitor, and if I drag it back to the 4K monitor, the icons are not rescaled and I am back with the same problem.
I am still investigating how to solve this problem of PreviewForm. With the debugger I see that PreviewForm has the right FCurrentPPI = 192 et FScaleFactor = 2
FYI: Aside of this problem, I have everything ok in my application for handle drag from monitors with various DPI. So I see no other problem of configuration.
There is a patch available for RB 20.04 which resolves an issue with toolbar/menus being double-scaled in some cases. This is perhaps what is happening in the first case above. It looks like in the screen shot either the buttons are not scaled or the font is double-scaled.
In your screen shot the toolbar items are scaled - you can see this in the highlight-rectangle for the 2 selected buttons. The icons are not scaled. The Delphi ImageList is not DPI aware.
The plan is to continue improving DPI support. Windows API has been evolving its DPI support, the Delphi VCL and FMX libraries are following suit. Delphi 10.4 introduces new VirtualImageList and ImageCollection classes designed to implement DPI aware icons. We're researching using these new classes for a future RB release.
Best regards,
Nard Moseley Digital Metaphors www.digital-metaphors.com
Thanks for your explanation. The problem I have on my 4K screen is effectively that the icons are not scaled.
FYI : if it can help you to build a patch quickly: in places where there are plenty of icons I do not want to migrate to image collections, I use in the Create function (DPI being the current DPI of the form) :
if DPI <> 96 then ResizeBitmap(btnXXX.Glyph, MulDiv(btnXXX.Glyph.Width, DPI, 96), Muldiv(btnXXX.Glyph.Height, DPI, 96));
And furthermore, to handle DPI change between monitors, here is a simplified version of what I do:
procedure XXX.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, NewDPI: Integer); begin if oldDPI <> DPI then begin j := MDIChildCount - 1; for k := j downto 0 do begin try if MDIChildren[k] <> nil then begin for i := MDIChildren[k].ControlCount - 1 downto 0 do begin ResizeControls(MDIChildren[k].Controls[i] as TControl, oldDPI, DPI); end; end; except // end; end; end; end;
The function to resize the icons recusively:
procedure XXX.ResizeControls(const AControl: TControl; oldDPI: integer; newDPI: integer); var i, j: Integer; begin if (AControl = nil) or (newDPI = oldDPI) then Exit; if AControl is TWinControl then begin for i := 0 to TWinControl(AControl).ControlCount-1 do ResizeControls(TWinControl(AControl).Controls[i], oldDPI, newDPI); end; if (AControl is TBitBtn) then DMStyle.ResizeBitmap((AControl as TBitBtn).Glyph, MulDiv((AControl as TBitBtn).Glyph.Width, newDPI, oldDPI), Muldiv((AControl as TBitBtn).Glyph.Height, newDPI, oldDPI)) else if (AControl is TSpeedButton) then DMStyle.ResizeBitmap((AControl as TSpeedButton).Glyph, MulDiv((AControl as TSpeedButton).Glyph.Width, newDPI, oldDPI), Muldiv((AControl as TSpeedButton).Glyph.Height, newDPI, oldDPI)) end;
=> you could use this approach at short term, and migrate later to proper high resolution icons, because the usability of the icons bar is really faulty with such small icons.
Comments
I'm testing with Delphi 10.4 and RB 20.03 and the preview toolbar is scaling correctly.
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
I have the same kind of problem as Frank:
I am with all versions updated: Delphi 10.4.1 and RB 20.04
My monitor is 4K with Windows Zoom at 300%.
If I drag the preview window to another monitor Full HD with zoom at 150%, everything is ok on this other monitor, and if I drag it back to the 4K monitor, the icons are not rescaled and I am back with the same problem.
My manifest is using PerMonitorv2
Gilles Boussin
I am still investigating how to solve this problem of PreviewForm.
With the debugger I see that PreviewForm has the right FCurrentPPI = 192 et FScaleFactor = 2
FYI: Aside of this problem, I have everything ok in my application for handle drag from monitors with various DPI. So I see no other problem of configuration.
I am looking forward to your answer.
Regards,
Gilles
There is a patch available for RB 20.04 which resolves an issue with toolbar/menus being double-scaled in some cases. This is perhaps what is happening in the first case above. It looks like in the screen shot either the buttons are not scaled or the font is double-scaled.
In your screen shot the toolbar items are scaled - you can see this in the highlight-rectangle for the 2 selected buttons. The icons are not scaled. The Delphi ImageList is not DPI aware.
The plan is to continue improving DPI support. Windows API has been evolving its DPI support, the Delphi VCL and FMX libraries are following suit. Delphi 10.4 introduces new VirtualImageList and ImageCollection classes designed to implement DPI aware icons. We're researching using these new classes for a future RB release.
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Thanks for your explanation.
The problem I have on my 4K screen is effectively that the icons are not scaled.
FYI : if it can help you to build a patch quickly: in places where there are plenty of icons I do not want to migrate to image collections, I use in the Create function (DPI being the current DPI of the form) :
if DPI <> 96 then ResizeBitmap(btnXXX.Glyph, MulDiv(btnXXX.Glyph.Width, DPI, 96), Muldiv(btnXXX.Glyph.Height, DPI, 96));
procedure ResizeBitmap(Bitmap: TBitmap; NewWidth, NewHeight: integer; ForceSquare: boolean = false);
var
buffer: TBitmap;
begin
buffer := TBitmap.Create;
try
buffer.SetSize(NewWidth, NewHeight);
buffer.Canvas.StretchDraw(Rect(0, 0, NewWidth, NewHeight), Bitmap);
Bitmap.SetSize(NewWidth, NewHeight);
Bitmap.Canvas.Draw(0, 0, buffer);
finally
buffer.Free;
end;
end;
And furthermore, to handle DPI change between monitors, here is a simplified version of what I do:
procedure XXX.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI,
NewDPI: Integer);
begin
if oldDPI <> DPI then begin
j := MDIChildCount - 1;
for k := j downto 0 do begin
try
if MDIChildren[k] <> nil then begin
for i := MDIChildren[k].ControlCount - 1 downto 0 do
begin
ResizeControls(MDIChildren[k].Controls[i] as TControl, oldDPI, DPI);
end;
end;
except
//
end;
end;
end;
end;
The function to resize the icons recusively:
procedure XXX.ResizeControls(const AControl: TControl; oldDPI: integer; newDPI: integer);
var
i, j: Integer;
begin
if (AControl = nil) or (newDPI = oldDPI) then Exit;
if AControl is TWinControl then begin
for i := 0 to TWinControl(AControl).ControlCount-1 do
ResizeControls(TWinControl(AControl).Controls[i], oldDPI, newDPI);
end;
if (AControl is TBitBtn) then
DMStyle.ResizeBitmap((AControl as TBitBtn).Glyph, MulDiv((AControl as TBitBtn).Glyph.Width, newDPI, oldDPI), Muldiv((AControl as TBitBtn).Glyph.Height, newDPI, oldDPI))
else if (AControl is TSpeedButton) then
DMStyle.ResizeBitmap((AControl as TSpeedButton).Glyph, MulDiv((AControl as TSpeedButton).Glyph.Width, newDPI, oldDPI), Muldiv((AControl as TSpeedButton).Glyph.Height, newDPI, oldDPI))
end;
=> you could use this approach at short term, and migrate later to proper high resolution icons, because the usability of the icons bar is really faulty with such small icons.
Gilles