I had problems in my app before because my forms are StayOnTop, and I change
it to fsNormal style and override CreateParams method:
procedure TMyBaseForm.CreateParams(var Params: TCreateParams);
begin
inherited;
if Assigned(Owner) and (Owner <> Application) then
Params.WndParent := TWinControl(Owner).Handle
else
if Assigned( Application.MainForm ) then
Params.WndParent := Application.MainForm.Handle;
end;
But there are a problem now: if I minimize my main menu form, the forms that
are shown don't be minimized (before, when formstyle was fsStayOnTop, the
forms were minimized well).
And there are another problem. If all forms are minimized, and I restore a
single form, main form is not restored automatically.
My overriding CreateParams method is wrong? How can I to minimize all forms
when the main form is minimized? And if I restore a form, restoring the main
form automatically (if main form is minimized)?
Thanks in advance
----------------------------------
Departamento Desarrollo I+D
GEINFOR, S.L.
The standard behaviour really depends on all forms being owned by the
Application window. When you try to minimize the main form the VCL traps the
request, hides the main form and minimizes the Application window instead.
Windows then automatically hides all windows owned by the Application window
(those that have Params.WndParent = Application.Handle, the default).
> And there are another problem. If all forms are minimized, and I restore a
> single form, main form is not restored automatically.
I think you are best served by cutting the Application window out of the
picture completely. For this you need to modify the main form a bit and also
hide the Application window:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindow( Application.Handle, SW_HIDE );
SetWindowLong( Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.Handle, GWL_EXSTYLE) or
WS_EX_TOOLWINDOW );
ShowWindow( Application.Handle, SW_SHOW );
end;
Procedure TForm1.WMSyscommand(Var msg: TWmSysCommand);
Begin
Case (msg.cmdtype and $FFF0) of
SC_MINIMIZE:
ShowWindow( handle, SW_MINIMIZE );
SC_RESTORE:
ShowWindow( handle, SW_RESTORE )
Else
inherited;
End;
End;
You should also override the main forms CreateParams and set its WndParent to
GetDesktopWindow and perhaps also add the WS_EX_APPWINDOW style to
Params.ExStyle. This way the main form now owns the taskbar button. If you
minize it it will now truely minimize and that should also automatically hide
all forms it is WndParent for.
Note that your scheme has two weaknesses:
1. The window handle of the main form can change if you change some of the
forms properties (like Borderstyle, Formstyle, Bordericons). Any existing forms
that use the main forms handle as WndParent would get "disconnected" from the
main form when that happens. I think this is one of the main reasons why
Borland introduced the Application window in the first place.
2. All dialogs from the Dialogs unit (including exception dialogs shown by code
out of your control) will still use the Application window as API owner. That
can cause problems with dialogs coming up behind the active form, or getting
hidden behind a form if the user switches from your app to another and back.
If you are using Delphi 2005 look at the PopupMode and PopupParent properties.
--
Peter Below (TeamB)
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be
I override CreateParam because if the simple form is fsNormal and click in
app main form, the simple form is sent to back. Due to this functionality, I
override CreateParams to assign Params.WndParent :=
TWinControl(Owner).Handle. I dont use fsStayOnTop formstyle because when a
form of a another app is shown modally, more times this forms appears BEHIND
(in WinXP this problem occurs frequently).
There are another way to implement that functionality using formstyle
fsNormal, i.e. if the user clicks on app main form, a single form don't
appears BEHIND the main form?
Regards
----------------------------------
Departamento Desarrollo I+D
GEINFOR, S.L.
"Peter Below (TeamB)" <10011...@compuXXserve.com> escribió en el mensaje
news:VA.0000bd4...@nomail.please...
No, the way you are using now is the only one available to fix relative Z-Order
the way you want it.
Okey. Then I have a doubt about you wrote before:
> 2. All dialogs from the Dialogs unit (including exception dialogs shown by
> code
> out of your control) will still use the Application window as API owner.
> That
> can cause problems with dialogs coming up behind the active form, or
> getting
> hidden behind a form if the user switches from your app to another and
> back.
It's possible to create a dialog programmatically (of Dialogs unit) and
change some properties to avoid this problems?
Like:
with TOpenDialog.Create(Self) do
begin
//Change properties
.....
Free;
end;
No, it is not that easy, unfortunately. You have to derive a new class from
TOPenDialog (and another from TSavedialog, etc.) and override a method so you
can change the API parent before the dialog is displayed. These dialogs are not
Delphi forms, they are wrappers around API functions that in turn display a
Windows-internal dialog.
The modification required is simple: you override the TaskModalDialog method
all the common dialog classes have and change a field in the API record that
gets passed to the API function for this dialog. For an open dialog this would
look like this:
type
TNewOpenDialog = class(TOpenDialog)
protected
function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
override;
end;
function TNewOpenDialog.TaskModalDialog(DialogFunc: Pointer;
var DialogData): Bool;
begin
if Assigned(Owner) and (Owner is TWinControl) then
TOpenFilename( DialogData).hWndOwner := TWinControl(Owner).Handle;
result := inherited TaskModalDialog( DialogFunc, DialogData );
end;
The only difference between the dialog classes is the type of the record you
need to cast DialogData to. Look at the original classes in the Dialogs unit to
see which record type they use. You need to add the CommDlg unit to your uses
clause for the record declarations.
----------------------------------
Departamento Desarrollo I+D
GEINFOR, S.L.
"Peter Below (TeamB)" <10011...@compuXXserve.com> escribió en el mensaje
news:VA.0000bd5...@nomail.please...
I override CreateParams and add the code you wrote of FormCreate &
WMSyscommand, and solve my problem. But occurs that if I show a form
modally, and show my own form dialog to show a message to a user (before
close the form), the focus goes away my app, and goes to the prior app that
is running.
For example:
procedure TSimpleForm.DoIt;
begin
MyFormDialog.Create('Bye!').ShowModal;
ModalResult := mrOk;
end;
When I close MyFormDialog, and close SimpleForm, the focus don't go to the
main form of my app, else the prior app (if I execute my app in Delphi IDE,
the focus goes to Delphi, and not to my app). In my forms shown not modal,
this behavior don't occurs never.
Can you help me to avoid this behavior?
Regards,
----------------------------------
Departamento Desarrollo I+D
GEINFOR, S.L.
"Peter Below (TeamB)" <10011...@compuXXserve.com> escribió en el mensaje
news:VA.0000bd4...@nomail.please...
I have no idea why it happens, sorry. If you are using XP as platform i would
not even be able to reproduce it given a test app (since i only have Win2K
available). The best i can tell you is to simply call the BringToFront method
(or SetForegroundWindow) after the ShowModal call that showed TSimpleForm
returns.
If I show a form (no modal) and when I push Close button, I show a progress
bar form before close (to perform some actions) the focus don't go to the
main form of my app, else the prior app (for example: Borland Delphi IDE). I
solve this doing a Self.SetFocus before close this form.
But if I need to show a barprogress form in CREATE of a form (because I need
to perform actions that costs a lot of time) and close it in FORM SHOW
event, I can not to solve this problem. Even I perform a Self.SetFocus, when
I close this form, the focus leave my app ever.
My code of main form is the next one:
procedure TMainForm.FormCreate(Sender: TObject);
begin
inherited;
ShowWindow( Application.Handle, SW_HIDE );
SetWindowLong( Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.Handle, GWL_EXSTYLE) or
WS_EX_TOOLWINDOW );
ShowWindow( Application.Handle, SW_SHOW );
end;
procedure TMainForm.WMSysCommand(var Msg: TWMSysCommand);
begin
inherited;
Case (msg.cmdtype and $FFF0) of
SC_MINIMIZE:
ShowWindow( handle, SW_MINIMIZE );
SC_RESTORE:
//ShowWindow( handle, SW_RESTORE )
ShowWindow( handle, SW_MAXIMIZE )
Else
inherited;
End;
end;
procedure TMainForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := GetDesktopWindow;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;
Can you help me?
Thanks in advance.
----------------------------------
Departamento Desarrollo I+D
GEINFOR, S.L.
"Peter Below (TeamB)" <10011...@compuXXserve.com> escribió en el mensaje
news:VA.0000bd6...@nomail.please...
I'm sorry. I want to say:
If I show a form (MODAL) and ...
NOTE : My barprogres form have override the CreateParams as follows:
procedure TFrmFormularioBase.CreateParams(var Params: TCreateParams);
begin
inherited;
if Assigned(Owner) and (Owner <> Application) then
Params.WndParent := TWinControl(Owner).Handle
else
if Assigned( Application.MainForm ) then
Params.WndParent := Application.MainForm.Handle;
end;
Regards
I just had a similar effect in a program of mine (which uses the default form
ownership, no modified CreateParams around anywhere) today at work (Win2K).
Windows just has gotten worse in keeping track of window Z order with every
version (and every patch it seems <g>).
> But if I need to show a barprogress form in CREATE of a form (because I need
> to perform actions that costs a lot of time) and close it in FORM SHOW
> event, I can not to solve this problem. Even I perform a Self.SetFocus, when
> I close this form, the focus leave my app ever.
That is a timing problem, you disrupt the normal sequence of message processing
done when a window is created. You can solve it by using the OnCreate or OnShow
events of the form to post (PostMessage) a user message (WM_USER + something)
to the form. In the handler for the message you then do your lengthy task plus
showing of the progress form. When the custom message is delivered the sequence
of step run during the form creation has completed and focus has been
established to some control.
Then it's not possible to force that my app goes to the top (Z order)?
It's possible that using a user message (WM_USER + something) to get that my
app goes to the top in this case to avoid this ugly behavior? If yes, can
you explain a little more how to perform this?
Regards
"Peter Below (TeamB)" <10011...@compuXXserve.com> escribió en el mensaje
news:VA.0000bd8...@nomail.please...
That is to be expected, when the messagebox closes *no* control in your
application has the focus, since the form is not visible yet at that point.
Windows then simply picks another visible window to come to the front.
>
> Then it's not possible to force that my app goes to the top (Z order)?
> It's possible that using a user message (WM_USER + something) to get that my
> app goes to the top in this case to avoid this ugly behavior? If yes, can
> you explain a little more how to perform this?
The best strategy would be to not show the messagebox from the OnCreate event.
Instead post (POstMessage) a user message to the form and show the dialog from
the handler for this message. At that point the form will be visible, so the
problem should go away. Also do not use Application.Messagebox, use
Windows.Messagebox and use the forms Handle as first parameter.