Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi disable form while loading

Tags:

delphi

tform

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.

like image 320
Andrey Avatar asked Jul 06 '13 16:07

Andrey


4 Answers

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.

like image 142
Remy Lebeau Avatar answered Nov 05 '22 06:11

Remy Lebeau


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:

  1. Before you call ShowModal, pass the task to the form. For example, pass a TProc to the constructor of the progress form.
  2. Override the progress form's 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.
  3. When the form handles that message, invoke the task that was passed to the constructor.

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.

like image 20
David Heffernan Avatar answered Nov 05 '22 06:11

David Heffernan


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;
like image 2
Asad Alamdar Avatar answered Nov 05 '22 08:11

Asad Alamdar


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.
like image 1
Jacek Krawczyk Avatar answered Nov 05 '22 07:11

Jacek Krawczyk