0

i have the current scenario, im using omnithreadlibrary for some generic background work like this:

TMethod = procedure of object;

TThreadExecuter = class;

IPresentationAnimation = interface
  ['{57DB6925-5A8B-4B2B-9CDD-0D45AA645592}']
  procedure IsBusy();
  procedure IsAvaliable();
end;

procedure TThreadExecuter.Execute(AMethod: TMethod); overload;
var ATask : IOmniTaskControl;
begin
  ATask := CreateTask(
    procedure(const ATask : IOmniTask) begin AMethod(); end
  ).OnTerminated(
    procedure begin ATask := nil; end
  ).Unobserved().Run();

  while Assigned(ATask) do
    begin
      Sleep(10);
      Application.ProcessMessages;
    end;
end;

procedure TThreadExecuter.Execute(ASender: TCustomForm; AMethod: TMethod); overload;
var AAnimator : IPresentationAnimation;
begin
  if(Assigned(ASender)) then
    begin
      TInterfaceConsolidation.Implements(ASender, IPresentationAnimation, AAnimator, False);
      if(Assigned(AAnimator)) then AAnimator.IsBusy()
      else ASender.Enabled := False;
    end;
  try
    Self.Execute(AMethod);
  finally
    if(Assigned(ASender)) then
      begin
        if(Assigned(AAnimator)) then AAnimator.IsAvaliable()
        else ASender.Enabled := True;
      end;
  end;
end;

so before i start executing i block the interface like this:

TMyForm = class(TForm, IPresentationAnimation);

procedure TMyForm.LoadData();
begin
  TThreadExecuter.Execute(Self, Self.List);
end;

procedure TMyForm.IsBusy();
begin
  try
    Self.FWorker := TPresentationFormWorker.Create(Self);
    Self.FWorker.Parent := Self;
    Self.FWorker.Show();
  finally
    Self.Enabled := False;
  end;
end;

and when the thread finish i release the block like this:

procedure TMyForm.IsAvaliable();
begin
  try
    Self.FWorker.Release();
  finally
    Self.Enabled := True;
  end;
end;

note: TPresentationFormWorker is a animated form that i put in form of the busy one.

the problem is that when the form is "busy" executing the thread even after i disable it, i can still interact with him, for example:

  • i can click in any button and when the thread finish the execution the action of the button are triggered;
  • i can typing in any control, e.g a Edit some nonsense information and when the thread finish the execution the content i provided to the control are erased back to before (ui rollback? lol);

so my guess is that while the thread are working thanks to the application.processmessages the interaction i made to the disable form are sended to the queue and once the thread finish they are all send back to the form.

my question is: is possible to actually disable the form, when i say disable i mean block all messages until certain point that i manually allow that can start accept again?

thx in advance.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
kabstergo
  • 761
  • 4
  • 16
  • What you are saying you are doing does not fit with what you are reporting is happening. We need to see more code - ideally complete code that replicates the problem. Setting a form to `.Enabled := false` should not allow you to modify or operate anything on the form. What is `TThreadExecuter`? Is it a `TThread` descendent? We need to see more information with context for all of this code - where and how is it all being called? That `Application.ProcessMessages` loop does not inspire confidence... – J... Feb 06 '15 at 19:16
  • thx for the attention, i added more code as you asked. – kabstergo Feb 06 '15 at 19:58
  • Just a simple solution: Do it like the mobile apps does it. Hide the form content with a "curtain" (rectangle, shape with opacity). After the thread is finished hide this "curtain". Place an AniIndicator and a Label on that curtain and your users will have some entertainment and stay informed on whats going on while waiting ... also you can get rid off that awful `Application.ProcessMessages` – Sir Rufo Feb 06 '15 at 20:09
  • `Form.Enabled := False`? – David Heffernan Feb 07 '15 at 10:04
  • i already do that, and based of my past experience disabling the form by this property doesn't prevent anything, e.g if the user double click fast a button the second click will be processed when the action of the first is concluded. again couse all the messages are waiting in the queue – kabstergo Feb 07 '15 at 10:13
  • That doesn't make much sense, interactions with a disabled form should only yield a 'beep' when messages are normally processed, The system does not post input messages to a disabled window in the first place. – Sertac Akyuz Feb 07 '15 at 14:20
  • `if the user double click fast a button the second click will be processed when the action of the first is concluded`. Well that's because you are using the evil `Application.Processmessages`... – whosrdaddy Feb 07 '15 at 15:54
  • @whosrdaddy but that is exactly my point, how this happend if the form is disabled, you saying that if i disable a button, make a loop with application.processmessages in it, during this time even with button disable i can click on it and the messages will be accepted? – kabstergo Feb 07 '15 at 16:34
  • @kabstergo No, a disabled window is disabled - if your window is accepting input then it is not disabled. Put a breakpoint on any line that enables the form and see where the call came from. You say this happens when you click quickly in succession; most likely this means you are doing a lot of processing before reaching the point where the form is disabled. Disabling the form first might be a solution. – J... Feb 09 '15 at 12:26
  • check this out: http://stackoverflow.com/questions/28408953/why-delphi-allow-this-behaviour same question with a simplified approach – kabstergo Feb 09 '15 at 12:27

0 Answers0