How to prevent the interface from being used during operations...

I have built a form that's being displayed during a lenghty operation.

it is created and destroyed with these two functions:

  procedure ShowWaitMessage(WaitMessage : string = 'Please wait...');

this function simply creates/shows a wait message.

  procedure HideWaitMessage(ShowDone: Boolean = True);

This hides/destroys the wait form.

When the form is shown, the user can always press some button in the other forms of the app, bypassing the wait form.

How do i prevent the interface from being used while the waitform is shown? i want it to be done when the form is displayed, and to be done automaticly, so i dont have to set enabled := false for every component of every form manually.

is there a quick function call i can use to enable / disbale the interface for the entire application?

topkapi
topkapiAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

LischkeCommented:
Hi Topkapi,

the VCL has a pair of functions which are designed to do what you need: display a window modeless (so the application doesn't block) but prevent other windows in the program from being used. The functions are DisableTaskWindows and EnableTaskWindows.

Ciao, Mike
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
LischkeCommented:
Oh I just saw there's no help in the help file so look at this sample code:

procedure TProjectForm.Execute;

var CanProceed: Boolean;

begin
  if GlobalSettings.AutoSaveEditor then CanProceed := SaveAll
                                   else CanProceed := True;
  if CanProceed then
  begin
    FindCoreEdits;
    with ProjectSettings do
    begin
      // make sure the target edits exist (all others are hiddenly loaded if necessary)
      if GenerateLexer then GetEdit(2);
      if GenerateParser then GetEdit(5);
    end;
    FWindowList := DisableTaskWindows(Application.Handle);
    CompileDialog.Show;
    CompileDialog.DoGenerate(Self);
  end;
end;

//-----------------------------------------------------------------------------

procedure TProjectForm.GeneratingDone;

const ErrorTypes = [mtError, mtSyntaxError, mtSemanticError, mtFatalError];

var I: Integer;
    MI: PMessageInfo;

begin
  if Assigned(FWindowList) then
  begin
    EnableTaskWindows(FWindowList);
    FWindowList := nil;
  end;

  if FErrors > 0 then
  begin
    // there were errors -> mark line in editor
    for I := 0 to MessageList.Items.Count - 1 do
      if Assigned(MessageList.Items.Objects[I]) and
         (PMessageInfo(MessageList.Items.Objects[I]).Code in ErrorTypes) and
         (PMessageInfo(MessageList.Items.Objects[I]).Source <> '') then
      begin
        MI := PMessageInfo(MessageList.Items.Objects[I]);
        ShowMarkedEdit(MI);
        Break;
      end;
  end
  else FocusEdit(FCurrentEdit);
end;


Ciao, Mike
0
kretzschmarCommented:
hi topkapi,

just disable the form during the your waitform is shown like

you can iterate through the screen.forms and disable the forms
(all embedded controls are then also disabled)

meikl
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

topkapiAuthor Commented:
just one question: What is the type of FWindowList?

0
topkapiAuthor Commented:
the DisableTaskWindows approach does not prevent me from clicking on buttons. (the button is not pressed, but after the operation is completed, and enabletaskwindows is called, the buttonhandler gets called anyway..)

trying the screen.forms approach...
0
LischkeCommented:
FWindowList is just a pointer. You need to store the return value of DisableTaskWindow to restore the state correctly.

Meikl, your suggestion is interesting too. After disabling can you still bring those forms to front or do they stay in the same z order?

Ciao, Mike
0
topkapiAuthor Commented:
done

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := False;

with

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := True;

but that also doesn't work. after i press a button, the action still executes after the operation.

do i have to clear a message queue or something? or can i reroute the messages to the waitform and then do nothing if a message is fired?
0
topkapiAuthor Commented:
done

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := False;

with

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := True;

but that also doesn't work. after i press a button, the action still executes after the operation.

do i have to clear a message queue or something? or can i reroute the messages to the waitform and then do nothing if a message is fired?
0
topkapiAuthor Commented:
this is the code for the functions, if you are intrested...

unit RCKWait;

{-------------------------------------------------------------------------------

  Name        : Unit Wait
  Descr       : One function to display a Waiting message (ShowWaitMessage),
                and one to remove it (HideWaitMessage) ;-)

                Use this unit to provide some visual feedback during lengthy
                operations.

  Last Update : Januari 2000

  Copyright   :

      Copyright© 2000 Remco Christiaan Kapinga.

      This software is created by Remco Christiaan Kapinga. You can reach
      me via E-Mail on the following address :  r.kapinga@cable.a2000.nl.
      On my homepage (http://people.a2000.nl/rkapinga)  you can find some
      more code samples.

      This software is free  software;  you  can  redistribute it  and/or
      modify  it under  the  terms of the  GNU General Public License  as
      published  by the Free Software Foundation; either version 2 of the
      License, or (at your option) any later version.

      This program is distributed in the hope that it will be useful, but
      WITHOUT   ANY  WARRANTY;  without  even  the  implied  warranty  of
      MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      General Public License for more details.

      You  can find  a copy  of the  GNU  General  Public License  on the
      following web site : http://www.gnu.org/copyleft/gpl.html

-------------------------------------------------------------------------------}

interface

uses
  Windows, Classes, Forms, SysUtils, StdCtrls, ExtCtrls, Controls;

procedure ShowWaitMessage(WaitMessage : string = 'Please wait...');
procedure HideWaitMessage(ShowDone: Boolean = True);

var
  WaitForm  : TForm;
  WaitLabel : TLabel;
  WaitIcon  : TImage;
  OriginalCursor : TCursor;
  // FWindowList : Pointer;

implementation

procedure ShowWaitMessage(WaitMessage: string);
{ var
  I: integer; }
begin
  // Make sure there is displayed something
  if Length(Trim(WaitMessage)) = 0 then
    WaitMessage := 'Please wait...';

  // Check to see if it's not already created
  if WaitForm = nil then
  begin
    // Create WaitForm ...
    WaitForm := TForm.Create(Application);
    with WaitForm do
    begin
      // Place in Center of Screen
      Position  := poScreenCenter;

      // Place above all other windows
      FormStyle := fsStayOnTop;

      // Make the window caption-less
      SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and not WS_CAPTION);

      SetBounds(Left, Top, 300, 50);
      // Width := 300;
      // Height := 50;
      ClientHeight := Height;
    end;

    // Create WaitIcon
    WaitIcon := TImage.Create(Application);
    with WaitIcon do
    begin
      Parent := WaitForm;
      Align := alLeft;
      Width := 42;
      Center := True;
      Picture.Icon := Application.Icon;
      Transparent := True;
    end;

    // Create WaitLabel
    WaitLabel := TLabel.Create(Application);
    with WaitLabel do
    begin
      Parent := WaitForm;
      ParentFont := True;
      Font.Size := 11;
      Caption := WaitMessage;
      Alignment := taCenter;
      Layout := tlCenter;
      WordWrap := True;
      SetBounds(44, 0, 230, 50);
    end;

    // Change the cursor
    OriginalCursor := Screen.Cursor;
    Screen.Cursor := crHourGlass;

    // Disable button clicking in other forms while working...
    {
    FWindowList := DisableTaskWindows(Application.Handle);

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := False;
    }

    // Show the form
    WaitForm.Show;
    WaitForm.Update;

  end else begin
    // Form already exists, just update text
    with WaitLabel do
    begin
      Caption := WaitMessage;
      Alignment := taCenter;
      Layout := tlCenter;
      WordWrap := True;
      SetBounds(44, 0, 230, 50);
    end;

    WaitForm.Refresh;
  end;
end;

procedure HideWaitMessage(ShowDone: Boolean);
{ var
  I: integer; }
begin
  if WaitForm <> nil then
  begin

    if ShowDone then
    begin
      ShowWaitMessage('Done.');
      Sleep(200);
    end;

    // Remove WaitForm
    WaitForm.Hide;
    WaitForm.Free;
    WaitForm := nil;
    WaitIcon := nil;
    WaitLabel := nil;

    // Restore original cursor
    Screen.Cursor := OriginalCursor;

    // Enable button clicking in other forms...
    {
    if Assigned(FWindowList) then
      EnableTaskWindows(FWindowList);

    for I := 0 to Screen.FormCount -1 do
      Screen.Forms[I].Enabled := True;
    }

  end;
end;

initialization
  WaitForm := nil;
  WaitIcon := nil;
  WaitLabel := nil;
  OriginalCursor := Screen.Cursor;
  // FWindowList := nil;

finalization
  HideWaitMessage(False);

end.
0
LischkeCommented:
topkapi, you must doing something wrong. I just tried this code:

procedure TMainForm.Button2Click(Sender: TObject);

begin
  FWindowList := DisableTaskWindows(Application.Handle);
  TestForm.Show;
  Timer1.Enabled := True;
end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  EnableTaskWindows(FWindowList);
  Beep;
end;


and this works very well. No messages are accumulated.

Ciao, Mike
0
topkapiAuthor Commented:
what if you add another button, and press that during the wait?
0
LischkeCommented:
I tried your entire code too and it works perfectly with my system (Delphi 5 on WinNT4). In particular both solutions work (DisableTaskWindows and Screen.Forms).

I don't know what's wrong with your system. Are you messing with messages while the wait form is shown?

Ciao, Mike
0
topkapiAuthor Commented:
basicly i'm doing this:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    ShowWaitMessage('Loading file...');
    Sleep(1000);
  finally
    HideWaitMessage;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage('error');
end;

when i press the button1, the message is shown. when i click the button2 with the mouse) while the message is shown, then after button1click is finished, the error message is shown.

i'm using Delphi 5 under NT5. nothing funny with messages...

0
DrDelphiCommented:
Am I missing something here? Why don't you simply show the form modally?
0
topkapiAuthor Commented:
i am using

  FWindowList := DisableTaskWindows(Application.Handle);

(they are no longer commented out like in the code example)

0
topkapiAuthor Commented:
DrDelphi:

if you use ShowModal then the app is halted until you close the waitform (wich you can't, because it has no buttons or anything). i want to do some operation, while showing the waitform.
0
LischkeCommented:
The Sleep command is causing the problem. When using Sleep I also get click messages. Try using a timer to test.

Ciao, Mike
0
topkapiAuthor Commented:
why is sleep a problem? does it call application.procesmessages?

0
topkapiAuthor Commented:
i'm running a query to test now, but doesnt a query alwas prevent messages from being processed?
0
topkapiAuthor Commented:
(query took WAY to long ;-))

using a timer, it works now!
0
topkapiAuthor Commented:
Thanks!
0
LischkeCommented:
Hey, you are flooding my mail folder :-))

Fine that you got it working now and thank you for the A grading.

Concerning the sleep function. I assume it has to do with the way it works. When sleeping the application never handles any message and thus they are accumulated until the application again responses or the message queue is full. When using DisableTaskWindow then the application still processes message but discards all those for which the target window is disabled. Therefor nothing is accumulated.

Ciao, Mike
0
kretzschmarCommented:
to mike,

regarding mikes q:
After disabling can you still bring those forms to front or do they stay in the same z order?

didn't know, never tested it,
but the z-order i guess is independent from the form so it could be, that there manipulations are possible.

for this problem, it should work in the same manner as your accepted suggestion, which (your) is more elegant.

meikl
0
LischkeCommented:
Meikl,

in the process of finding a solution for topkapi I tried also your suggestion and it works equally well as mine. I cannot speak of side effects though, as I only have tested the DisableTaskWindow function, thoroughly.

Ciao, Mike
0
topkapiAuthor Commented:
where can i find soe documentation on DisableTaskWindows? delphi help doesn't mention it, neither does the msdn library from visual studio 6....
0
LischkeCommented:
DisableTaskWindows is an internal function. Look at ShowModal and you see that it is used there. I was also looking for a way to keep the application responding while effectly keep the user from accessing it.

Ciao, Mike
0
topkapiAuthor Commented:
Source of DisableTaskWindows is found in forms.pas...
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.