Reputation: 145
I have some vcl mdi application and I need to make some work inside it and show another not modal form of progress above it. And because this progress form is updated from some thread and have some buttons on it (to cancel operation), I update progress with application.ProcessMessages. During this process I need to disable all main form controls. I do it in this way:
MainForm.enabled := false;
... do some work here, update progress ...
MainForm.enabled := true;
Though, after this my main form goes under other windows applications which is not cool. If I remove this two lines enabled/disabled - it stays on top as it should be.
Any ideas how to fix it?
Upvotes: 0
Views: 1505
Reputation: 502
A simple BringTofront
works. It can be before or after setting enabled
to be true
.
MainForm.enabled := false;
// ... do some work here, update progress ...
MainForm.enabled := true;
MainForm.BringTofront;
or
MainForm.enabled := false;
// ... do some work here, update progress ...
MainForm.BringTofront;
MainForm.enabled := true;
Edit: As commented below, with the above code the main form will go behind the others before it becomes focused. This happens in Delphi 7 but seems not in Delphi 2009.
When the current active form is closed or becomes hidden, Delphi tries to switch to the main form. However, if the main form is disabled, Delphi cannot activate it and will move it to the back. The solution is fairly simple, just set Enabled
to be true
right before hiding or freeing the other form. There is no need to call BringTofront
.
MainForm.enabled := false;
ProgressForm.Show; // Or Application.CreateForm(...)
// ... do some work here, update progress ...
MainForm.enabled := true;
ProgressForm.Hide; // Or ProgressForm.Free;
Edit: Here is the Delphi code that causes this behavior:
procedure TCustomForm.CMShowingChanged(var Message: TMessage);
....
begin
....
NewActiveWindow := 0;
if (GetActiveWindow = Handle) and not IsIconic(Handle) then
NewActiveWindow := FindTopMostWindow(Handle);
if NewActiveWindow <> 0 then
begin
SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_HIDEWINDOW or
SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE);
SetActiveWindow(NewActiveWindow);
end else
ShowWindow(Handle, SW_HIDE);
....
end;
another fix is to handle the CM_SHOWINGCHANGED
message of the second form:
procedure CMSHOWINGCHANGED(var Message: TMessage); message CM_SHOWINGCHANGED;
procedure TProgressForm.CMSHOWINGCHANGED(var Message: TMessage);
begin
if not visible then
Application.MainForm.Enabled := True;
inherited;
end;
Upvotes: 2
Reputation: 145
Ok, looks I found the solution. PopupMode of the progress form set to pmAuto. Main form stays on top in this case.
It works in this way:
procedure TMainForm.DoSomenthing;
begin
enabled := false;
try
// open progress form
Include(ProgressFrm.FFormState, fsModal);
ProgressFrm.Show;
.... do something, update progress ....
// close progress form
ProgressFrm.Hide;
Exclude(ProgressFrm.FFormState, fsModal);
finally
enabled := true;
BringToFront;
end;
end;
Upvotes: 0