Link to home
Start Free TrialLog in
Avatar of topkapi
topkapi

asked on

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
ASKER CERTIFIED SOLUTION
Avatar of Lischke
Lischke

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Lischke
Lischke

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
Avatar of kretzschmar
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
Avatar of topkapi

ASKER

just one question: What is the type of FWindowList?

Avatar of topkapi

ASKER

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...
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
Avatar of topkapi

ASKER

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?
Avatar of topkapi

ASKER

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?
Avatar of topkapi

ASKER

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.
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
Avatar of topkapi

ASKER

what if you add another button, and press that during the wait?
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
Avatar of topkapi

ASKER

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...

Am I missing something here? Why don't you simply show the form modally?
Avatar of topkapi

ASKER

i am using

  FWindowList := DisableTaskWindows(Application.Handle);

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

Avatar of topkapi

ASKER

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.
The Sleep command is causing the problem. When using Sleep I also get click messages. Try using a timer to test.

Ciao, Mike
Avatar of topkapi

ASKER

why is sleep a problem? does it call application.procesmessages?

Avatar of topkapi

ASKER

i'm running a query to test now, but doesnt a query alwas prevent messages from being processed?
Avatar of topkapi

ASKER

(query took WAY to long ;-))

using a timer, it works now!
Avatar of topkapi

ASKER

Thanks!
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
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
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
Avatar of topkapi

ASKER

where can i find soe documentation on DisableTaskWindows? delphi help doesn't mention it, neither does the msdn library from visual studio 6....
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
Avatar of topkapi

ASKER

Source of DisableTaskWindows is found in forms.pas...