In my application, I have a main form, with the ability to load some images in database. While images is loading, I want to show a form, with the progress indicator (with bsNone border style).
But, if I show with form with ShowModal, execution of main form is stopped, so I can't to that.
If I call Show, user have access to all other form components, and it can be dangerous, while photo is not loaded completely.
I need to get the way, to disable everything on main form, while loading isn't completed.
Please, advice me, how it is possible.
Set the MainForm as the PopupParent for the progress form so that the MainForm can never appear on top of the progress form.  Then simply set MainForm.Enabled := False while the progress form is open and set MainForm.Enabled := True when the progress form is closed.
procedure TMainForm.ShowProgressForm;
begin
  with TProgressForm.Create(nil) do
  begin
    PopupParent := Self;
    OnClose := ProgressFormClose;
    Show;
  end;
  Enabled := False;
end;
procedure TMainForm.ProgressFormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  Enabled := True;
end;
This simulates howShowModal() behaves to the user (the MainForm is not user-interactive while the progress form is open), but without blocking the code.
As I explained in my other answer, putting the long running task into a thread other than the GUI thread is the ideal solution. The GUI thread should handle short running tasks so that it is always able to service the message queue in a timely fashion.
However, if you already have code that assumes that the long running task runs on the GUI thread, you may prefer to take a more expedient approach and postpone the re-factoring to threaded code. In which case, in my view, it is still better to use ShowModal to display your progress form.
But in order to make that work, you need to find a let the long running task execute inside the ShowModal call. You can do that as follows:
ShowModal, pass the task to the form. For example, pass a TProc to the constructor of the progress form.Activate method. This will get executed just before the ShowModal function starts its modal message loop. In the implementation of Activate, post a message to the form.Obviously you'll need to call ProcessMessages in your long running task, in order to keep the main GUI thread message queue serviced. Clearly you must already be doing that.
Set the PopupParent of child form = ParentForm
procedure TParentForm.Button1Click(Sender: TObject);
begin
ParentForm.Enabled:=False;
with Tform1.create(nil) do show;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ParentForm.Enabled := true;
form1.free;
end;
                        You may want to use  DisableTaskWindows and EnableTaskWindows functions. 
If you use simple ParentForm.Enabled := False for the parent form, you can still access all other forms, like the main form if it differs from ParentForm. It is obviously still dangerous.
Here is short sample:
interface
uses
  Vcl.Forms, Winapi.Windows, ...;
type
  TPleaseWait = class(TObject)
  private
    fWindowList: TTaskWindowList;
    fActiveWindow: HWND;
    fDialog: TPleaseWaitForm;
  public
    constructor Create;
    destructor Destroy; override;
  end;
implementation
constructor TPleaseWait.Create;
begin
  // Disable all displayed windows
  fWindowList := DisableTaskWindows(0);
  // Save the last active window
  fActiveWindow := GetActiveWindow;
  fDialog := TPleaseWaitForm.Create(nil);
  fDialog.Show;
end;
destructor TPleaseWait.Destroy;
const
  INVALID_HANDLE = 0;
begin
  fDialog.Close;
  fDialog.Free;
  // All windows are enabled now
  EnableTaskWindows(fWindowList);
  // That helps by enabling the last one form
  if (fActiveWindow <> INVALID_HANDLE) and IsWindow(fActiveWindow) then
    SetActiveWindow(fActiveWindow);
  inherited;
end;
end.
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With