How to block all incoming message to a form while thread is executing
Asked Answered
U

0

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.

Ulmer answered 6/2, 2015 at 19:0 Comment(10)
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...Welsh
thx for the attention, i added more code as you asked.Ulmer
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.ProcessMessagesKidder
Form.Enabled := False?Tello
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 queueUlmer
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.Weiland
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...Granophyre
@Granophyre 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?Ulmer
@Ulmer 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.Welsh
check this out: #28409453 same question with a simplified approachUlmer

© 2022 - 2024 — McMap. All rights reserved.