Delphi apps, form size varies on different machines - delphi

I've got a Delphi 7 app, on the WinXP development machine the form size is the same as it was designed.
However, running the app on a Vista machine, some forms have been enlarged 20-30%, leaving big blank spaces on the right and bottom edge of forms.
On one of our client's WinXP machine, the forms have shrink, causing scroll bars to show up on the forms.
On most other machines, it shows up OK.
The app does remember the form size that was last used on some forms, and uses it next time the form is opened, however even removing these settings, the default form size is still different to how it was designed.
Any ideas?

This sounds like a well known issue with Delphi forms and interactions with system font sizes.
The default behaviour of a Delphi form is to attempt to scale to respect the (runtime) user's desktop environment. This can have unintended and undesirable side effects however, and your "symptoms" sound like this could be what's going on in your case.
But all is not lost! The Scaled property (TRUE by default) can be set FALSE to prevent this, but I recommend you read that first article, and also consider The information in this article in order to determine whether this is the right solution in your case.

Large Fonts versus Small Fonts on the Vista machine maybe?

Use this code in OnCreate event for every your form:
if Win32Platform = VER_PLATFORM_WIN32_NT then
Font.Name := 'MS Shell Dlg 2'
else
Font.Name := 'MS Shell Dlg';

Related

Delphi 11.2 Patch 1 frames and High-DPI

I have encountered a problem with Delphi's multi monitor high-DPI support that I would welcome any insights you might have. I am using Delphi 11.2 patch 1 on a 5K monitor with Delphi's form designed set to Automatic (Screen PPI)
I have a small test project with a TDBAdvGrid and a TDBNavigator at the top of the form and a separate Tframe at the bottom of that form added at design time also having a TDBNavigator and a TDBAdvGrid on it. When I run the program initially it all looks fine.
As I said,I am designing on a 5K monitor (5120x2880) at 200% font scaling and I have a second monitor attached (1920x1080) at 100% font scaling. If I drag the form onto the second monitor the grid and navigator on the form appear to respond nearly as they should (just doesn't get the column widths quite correct) but the grid and the navigator in the TFrame don't.
Then if I drag the form back to the main monitor the TFrame is even more messed up
Do you have any recommendations on how to handle this? Should I be doing something with the main form's onBefore/OnAfterMonitorDPIChange events?
This high-DPI stuff all seems very much work in progress. And if I wanted to persist the column widths in an ini file, how would that work? Would I have to save it separately for each monitors PPI settings?

icon on the taskbar does not move to second monitor

I recently got a new development computer with again 2 monitors, but unfortunate it has windows 10.
Now I also have some tools still developed in Delphi 7 and they work but with one annoying problem.
When I start an Delphi 7 application the icon on the taskbar does not move to the second monitor.
The taskbar is setup to show icons on the taskbar of the monitor they are open. This works for all applications, except for the Delphi 7 applications.
The icon always stays on the primary monitor.
I have the source available, so I wonder is there something I have to put into the source code, or setup some property, to get this working ?
Googling this bring up lots of cases where the form does not moves to the second monitor, but I did not find anything about the icon on the taskbar.
This is because the window handle associated with the taskbar button is the window handle owned by the Application object rather than the window handle of your main form.
In later versions of Delphi you would write Application.MainFormOnTaskBar := True in your .dpr file and that would change behaviour so that the taskbar button was associated with your main form instead. I believe that MainFormOnTaskBar was introduced in Delphi 2007.
Migrating to a modern version of Delphi is the ideal way to solve the problem. If you cannot do that then you'll need to hack your way around the VCL code to ensure that the main form's window handle is the one associated with the taskbar button. That's not likely to be an easy job. Fundamentally, you are paying the price for continuing to develop with tools that are long out of date.
As Remy points out there isn't much hacking required to do the bare minimum. Change the window style of the Application window to remove the WS_EX_APPWINDOW style, and have the main form override the CreateParams method to set its owner window to NULL, i.e. Params.WndParent := 0.
I suspect that the behaviour will not be quite as smooth as you'd get with a modern VCL app. For instance, the VCL has been modified to reduce the amount of window recreation it does which is more important now that the main window is associated with the taskbar button.

Why does scaling of controls differ between PC's?

I try to give the user a 'clean and simple' interface by hiding some elements. Only a small arrow denotes that he can expand some part of the main menu bar. When all is closed it looks like this:
When you open all it looks like this:
Each arrow is a SpeedButton thats sits on the left side of a panel. By clicking on the button the Width is toggled between the width of the Speedbutton (closed) and the width of the panel at design time (open). The width of the panel at designtime is stored as a constant. The procedure show_hide_controls handles this:
procedure TCompose_Main.show_hide_controls (key: string; Button: TSpeedButton; Panel: TPanel; width: Int32);
begin
if GPA.iKey [key] = 1
then Panel.Width := width // show panel, set panel to design width
else Panel.Width := Button.Width; // hide panel, set with to button width
Button.Glyph.Assign (nil);
Images_Left_Right.GetBitmap (GPA.iKey [key], Button.Glyph);
end; // show_hide_controls //
This routine is called as follows:
show_hide_controls ('Show Play Controls', // index to panel to show/hide
Enlarge_Play, // Speedbutton requesting the enlargement/hide
Panel_Play, // Panel to show/hide
cPlayWidth); // Width of panel when shown
Now several users report that part of the panel is hidden, like:
It seems that the operating system (Windows 7) plays some tricks with scaling. I'm not able to duplicate this error. Does anyone understand what is happening here? And is there a neat way to program against this in a settings independent way?
Update As GDF rightly pointed out in his answer it has to do with the scaling of the fonts (control panel > Display). This behaves somewhat weird on my machine. Changing it to 150% has a minor impact while changing it to 125% has a major impact. As you might have guessed I tested the first and not the second scaling. Only when a user reported that scaling back from 125% to 100% I could replicate his error on my machine.
I could not find a relation between fonts and the troubles I have as was suggested by several respendents. My system is still suffering from all the tests I did with Courier (not new), Segoe UI, Tahoma and MS Sans Serif :-D. Maybe indirectly because the controls are probably resized to accomodate the text.
How to handle this? I don't know, I'll start experimenting and will let you know if I find something.
Thanks to you all for your help!
If your problem is what I believe, you just stated the answer. Windows 7 plays with scaling certain fonts. When you install Win7 on a PC it checks the size of your monitor and makes the "default" scale setting either 100% or 125% depending on your monitor size. The problem is that at this same time it installs font files onto the computer. It uses a different font file for the different "default" for some of the fonts.
My guess is your app is using MS Sans Serif... this is one of the fonts that gets different font file installs depending on what scale Win7 is using as the (default).
To verify this have your users tell you want scale is set as the default, you can view this by right clicking the desktop and selecting "personalize" then "Display" at the bottom left.
The following link shows you how to change the in-use-font file back to the original
http://www.rlvision.com/misc/windows_7_font_bug.asp
However, I would make an attempt to get off of this font and update the layout elements to work as desired on Win7 as well as past OSes
This is what I think you are dealing with given the limited amount of information you have provided...
Update
Since you reminded me when you mentioned the different looks between 125% v 150%. I just wanted to make sure you were aware that the two different MS Sans Serif files looks better at different scales. One of the font files looks great at 100% and 150% but horrible at 125%. The other font file looks great at 125%, but horrible at 100 and 150%.
I don't quite remember which font file is which, but I know the 2 culprits are
1) SSERIFF.FON
2) SSERIFE.FON

How to make my Deskband's (Taskbar Toolbar) Form transparent

I'm working on a Windows Deskband in Delphi XE2 for Windows XP, Vista and 7 (Win32 and Win64)...
I've implemented all the necessary interfaces (ITrayDeskBand, IDeskBandInfo, IDeskBand2, IDeskBand) in my code, and that all works exactly as it should (there are no warnings on Vista/7 complaining about compatibility as others have experienced).
The problem I have is that my Deskband Form appears with a non-transparent band. Also, only certain Controls are displaying (in this case TBitBtn and TImage containing a PNG). I need it to display TEdit and TComboBox objects properly too, but they won't appear at all.
I've tried enabling GlassFrame and SheetOfGlass properties on my Form, but this doesn't help one bit.
Furthermore, the Form itself is exceeding the top boundary of the Taskbar, meaning you cannot (for example) resize the Taskbar if the cursor is in-line with the top of the Taskbar immediately above my Deskband.
I believe there is something Delphi's VCL TForm type is doing behind the scenes which renders the TForm type incompatible as a Deskband container... but this is just a suspicion.
Here's a screenshot illustrating the various problems:
As you can see (above), the Deskband's Form is pale (instead of Transparent), it overlaps the top of the Taskbar (preventing resizing and Autohide triggering when the Taskbar is "hidden")
Any ideas?
UPDATE 1
Okay, I have been playing around and noticed that a totally different behaviour is observed when creating a TToolBar control to be used for the Deskband, rather than a form:
Notice there are three TToolButton controls (with their text virtually invisible due to the Glass theme)? There should also be a TEdit and TComboBox between two separators, but these refuse to display at all.
Also notice the artefacting (the repetition of actual Taskbar Icons)?
I'm not sure if this is a step in the right direction or not, but it might help you (or others) to deduce a solution!
Okay... I've finally figured this out, and it is the most absurd thing I've ever come across.
I'm posting my findings here for the benefit of others (to save you going through the nuisance I've just been through).
To get all of the controls on your Deskband Form to display and function properly, simply set the Visible property of your Form (in the IDE designer) to True.
Ridiculous, I know, but it works and is easily repeatable.

Is it OK to hide Delphi's "Application" Window?

We just moved our application from a MDI container to a single document interface. Our users are used to using a "Windows" menu in the MDI parent to show windows side by side. We want to train them to right click on the Windows taskbar and use the window management functions there.
With Delphi applications we noticed that the windows shell leaves room for the hidden "Application" window. So if I only have two windows open it will arrange room for three. The Application window is not really shown but there is space left for it.
This is made worse by the fact that we have two different applications. If they only have one window open in each application and want to show them side by side windows will actually try to account for 4 windows.
So instead of seeing two windows each taking 1/2 of the screen I see two windows that take up 1/4 of the desktop and the rest of the screen is open.
I found that adding a line to hide the application window as my application starts up will fix this problem.
ShowWindow(Application.Handle, SW_HIDE);
Edit in case someone does not read
down to the answer. Based on Craig's
answer below I am setting the windows
style to WS_EX_TOOLWINDOW instead of
hiding the window.
SetWindowLong(Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
My (original) questions is: Is this safe (hiding the application window)? I'm wondering if I may be breaking something else by hiding the Application window. Are there any side effect I need to be aware of? Is there a better way to solve this issue?
I'm using Delphi 2007. The issues seem to be consistent across Windows XP, Vista, and 7.
Update: Some of the answers seem to think the problem is with the Application forms icon being visible. That is not the case. I already have MainFormOnTaskbar set to true.
Also if you are testing this be aware that the Delphi IDE (only tested with 2007) makes things worse. Try this. Open the Delphi IDE and two instances of notepad. Minimize the IDE but have both notepads un-minimized. Right click on choose Show Windows Side by Side. You will see each notepad take up 1/3 of the screen. Close the IDE and choose Show Windows Side by Side again and each will take up 1/2 half of the screen.
In Delphi 2007 (and above) the Application Window does not show on TaskBar at all if
Application.MainFormOnTaskbar := True;
line is in a project file (*.dpr). For example
begin
Application.Initialize;
Application.MainFormOnTaskbar := True; // <--
Application.CreateForm(TForm7, Form7);
Application.CreateForm(TForm8, Form8);
Application.Run;
end.
That is default setting for new applications, but this line is absent if you ported an application from previous Delphi version - you should add this line manually.
As long as MainFormOnTaskBar is true, you can fix the problem by adding this to your DPR:
SetWindowLong(Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
Later versions of Delphi automatically include the WS_EX_TOOLWINDOW flag when they create the TApplication handle.
I'm still using Delphi 7, and I've been using this technique in combination with the 'WndParent:=GetDesktopWindow' trick to get a taskbar button for each window, somewhat like Microsoft Office started doing since some version (I guess XP?)
I believe at this is the way that applications minimize to the system tray.

Resources