Delphi supports this type of forms by providing the FormStyle property for the TForm class. All you have to do is to set this property to fsStayOnTop. So why did I write this article? Well, there are a few things to consider:
- Using fsStayOnTop causes flickering of the form, because it recreates the window handle.
- If you have a Stay-On-Top-Form (ok, we'll call that a SOT form from now on), and then a modal dialog is displayed, (part of) the dialog will be hidden by the SOT form.
- If you activate another application, the SOT form may even remain on top of that application and usually that is not the intent.
So, somehow we'll have to deal with these situations.
- fsStayOnTop - First of all, let's have a look at how the FormStyle property works:
procedure TCustomForm.SetFormStyle(Value: TFormStyle); var OldStyle: TFormStyle; begin if FFormStyle <> Value then begin if (Value = fsMDIChild) and (Position = poDesigned) then Position := poDefault; if not (csDesigning in ComponentState) then DestroyHandle; OldStyle := FFormStyle; FFormStyle := Value; if ((Value = fsMDIForm) or (OldStyle = fsMDIForm)) and not Ctl3d then Color := NormalColor; if not (csDesigning in ComponentState) then UpdateControlState; if Value = fsMDIChild then Visible := True; end; end;
In the code snippet, I underlined the call to DestroyHandle. This causes the window handle of the form to be destroyed. If the form is visible, the handle will be needed immediately, which causes the form to flicker. If you allow the user to switch SOT on and off, it doesn't look too well.
The alternative is to use the WinSDK SetWindowPos routine to change SOT and GetWindowLong to see if a form is SOT.
- Dialogs - The problem with modal dialogs is, that they disable all other windows in the
application (See the TCustomForm.ShowModal method). So once the dialog is displayed and partially
or completely hidden by the SOT form, the user can't either move the SOT form or make it not-SOT, because
it is disabled. So he has to move the dialog, which is bad for his mood. Delphi offers the TApplication.NormalizeTopMosts
and TApplication.RestoreTopMosts methods to deal with this, but these are not called by ShowModal,
so you have to do this every time you activate a modal dialog. Moreover, standard messages (ShowMessage
function) will still be hidden behind the SOT form even then.
Personally, I think that the need to use NormalizeTopMosts isn't quite fair. I'd say, that if someone creates a problem, he's responsible to solve it too! But here, the SOT form causes the trouble, and it expects the modal dialog to solve the problem by using NormalizeTopMosts. And this means, you have to include many of those calls, which isn't really good programming practice.
The real problem here is merely the fact that the SOT window is disabled, as pointed out before. So the solution is simple. Each time a window is enabled or disabled, windows sends it a WM_ENABLE message. So the SOT form can supply a message handler, that temporarily makes it not-SOT, if it is disabled.
- Other applications - In most cases, a form is made SOT to make sure it is on top of other forms within the same application. But if another application is activated on top of it, you don't want that SOT form to hang around there. This can be solved by writing a message handler for the WM_ACTIVATEAPP message, which Windows sends to each window in an application when the application is activated or deactivated.
Now we have the basic ingredients for a form that implements a smooth SOT feature. I wrote a form class called TStayOnTopForm, based on the principles described above. Apart from implementing SOT, it also offers the possibility to add an item to the form's system menu (that's the menu you see if you right-click on the title bar of the form).
The class introduces the following public and members:
|Member type||Visibility||Accessibilty||Member name||Datatype||Description|
|property||published||Read/write||StayOnTop||Boolean||The StayOnTop property indicates whether the form should remain on top or not.|
|property||published||Read/Write||StayOnTopItem||Boolean||The StayOnTopItem indicates whether an item should be included in the system menu to allow the user to switch between SOT and not-SOT.|
|property||public||Read only||StayOnTopSuspended||Boolean||The StayOnTopSuspended property is true when the form is either disabled, or the application is not active. In this case the StayOnTop property may still be true, but the form is made not-SOT as long as StayOnTopSuspended is True. The value of the property is completely controlled by the form itself.|
You can download the source code for this class, as well as a demo program, from Code Central. With the information from this article, the source code for TStayOnTopForm (in unit uStayOnTopForm) should be understandable.
Article originally contributed by Peter Laman