Frage

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.

War es hilfreich?

Lösung

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.

Andere Tipps

First of all, the direct answer to your question.

I need to get the way, to disable everything on main form.

Set MainForm.Enabled to False to disable the window associated with the main form. And to re-enable set it to True instead.


Your fundamental problem however, is that you are executing long running tasks in the GUI thread. That's always a bad idea and the way out is to execute those long running tasks in a separate thread.

Once you move the long running tasks to a separate thread then you will find that ShowModal is exactly what you need to show your progress form.

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.

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.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top