Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

controls are still feeling your clicks 4

Status
Not open for further replies.

leopardo

Technical User
May 14, 2005
18
AR
Hello my Friends.

Working with D2 in W98SE.


The property "Enabled", does it really enable or disable the related control ???. Here's a simple example:

procedure Button1.OnClick(Sender: TObject);
begin
Button1.Enabled:= false;

... Do the process required, it takes some seconds

Button1.Enabled:= true;
end;

Simple code for preventing the user to re-start the execution of the process while it's running.

But If you click again (accidentally?) on this disabled button while the process is being executed, the process will be executed again after the line 'end' is reached. Furthermore, the number of times you click the button while it's disabled, the number of times the process will be executed.
This happens not only to buttons but to other controls too; checkboxes, TEdit's etc. Even though they look disabled, any action with the mouse or keystrokes on them, whill be evident when they become enabled again. What is happening and how can I turn them 'insensible' when they're disabled?.

I'll appreciate so much your comments. [morning]
 
It happens also if you set visible to false !!!

button1.visible := false;
.....
button1.visible := true;

sometimes it's a big problem for me too!!

I hope sombody can help us.

Giovanni Caramia
 
Well, gcaramia, while we wait for that one who help us, it's not bad idea preparing more coffee.

Leopardo [morning]
 
You could just check if the button is enabled before you execute the process, like this:
Code:
procedure Button1.OnClick(Sender: TObject);
begin
if Button1.Enabled = true then
begin
  Button1.Enabled:= false;
  ... Do the process required, it takes some seconds
  Button1.Enabled := true;
end;
end;
 
Cool idea but dosen't work.
Why?.
It seems Delphi (Delphi 2.0 at least) remembers you've clicked and calls the OnClick procedure after the previous OnClick was completed, so the if statement is always true !!!!!!.

I need more coffee.

Leopardo [morning]
 
I think it's due to mouse's buffer in windows but i don't know how to reduce it's dimensions to '0' only for the button i need.....
 
Too much coffe does not help your health so you can use a
workaround like this one (using timer):

Code:
procedure TForm1.Button1Click(Sender: TObject);
begin
  if button1.Tag <> 99 then  
    begin
      button1.Tag := 99;
      .........
      .........
      timer1.Enabled := true;
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled := false;
  button1.Tag := 0;
end;

your timer1 must have initially:
enabled = false
interval = 100
tag = 0

So you can go on in your work .... good work

Giovanni Caramia
 
Hey there
Prior to finding a workaround try to process the messages first.
Code:
button1.visible := false;
Application.ProcessMessages;
.....
button1.visible := true;
HTH

--- McMerfy
 
This may be a woolly answer, but I guess it's all down to message processing. When you click on the button then your OnClick routine is called, and if there is a lengthy process in here then this may keep Windows busy for a while...
As this process is running you click on the button again, but Windows does not process this new 'OnClick' message until it has finished handling the previous click, by which time the button is enabled again. By putting Application.ProcessMessages in your code then you should ensure that the second click of the button is handled while the first click is still being processed, and hence should be handled by Windows as a click on a disabled button.
Hope that made some sense

Steve
 
McMerfy, propblem is still there.
You can set invisible the button and process the message, but if you click on the form in the area where the button is placed (also if you don't see it), while the code of buttonclick is processing, that new click, is executed at the end of prior process.

Giovanni Caramia
 
Loved Friends.

I was disappeared in these days searching for an elegant solution of my problem and I've just gained a hole in my stomach due a lot of coffee drunk. [morning]
As gcaramia said, 'but the problem is still there'.
This is a bit frustrating. I said I work with Delphi 2.0, maybe in later versions this problem doesn't exist.
Anyway, I'm going to try a couple of tricks to fix this up. We'll see.

leopardo [pc3]
 
Hi leopardo,

Give this a try. All I have done here is change the onclick procedure of button1 while it is doing the processing. That what it will never be able to execute the Button1Click method whilst it is processing.

Let me know how it goes.
Adam


Code:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ButtonNil(Sender: Tobject);
  private

....

procedure TForm1.ButtonNil(Sender: Tobject);
begin
//do nothing
end;


procedure Button1.OnClick(Sender: TObject);
begin
 Button1.Enabled:= false;
 Button1.OnClick := ButtonNil;

 try
   ... Do the process required, it takes some seconds
 finally
   Button1.OnClick := Button1Click;
   Button1.Enabled:= true;
 end;
end;






------------------------------------
There's no place like 127.0.0.1
------------------------------------
 
A quick test shows that this feature exists in Delphi 7 (with Service Pack 2) as well. Maybe someone from Borland could explain.

Borland Delphi Help said:
VCL Reference
Enabled property (TControl)

TControl See also

Controls whether the control responds to mouse, keyboard, and timer events.

Delphi syntax:

property Enabled: Boolean;

C++ syntax:

__property bool Enabled = {read=GetEnabled, write=SetEnabled, stored=IsEnabledStored, default=1};

Description

Use Enabled to change the availability of the control to the user. To disable a control, set Enabled to false. Disabled controls appear dimmed. If Enabled is false, the control ignores mouse, keyboard, and timer events.

To re-enable a control, set Enabled to true. The control is no longer dimmed, and the user can use the control.

Clever workarounds are acceptable if this is the first version of Delphi to exhibit the problem, but when such a major problem exists in both versions 2 and 7 (and presumably in the intervening versions also), I think Borland should, as a matter of urgency, provide a professional solution. I have never experienced this problem with Microsoft tools (although, to be honest, I have never tested for it, but I will tomorrow).
 
Visual Basic 6.0, VisualBasic.net have same problem.
It's due to windows mouse's cache.

Giovanni Caramia
 
Don't see how this could be but this works fine in D7 :

drop a Tlabel,Tbutton and TTimer on a form and use the code hereunder. set the TTimer interval to 5000 milliseconds and not enabled.

Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation


{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
begin
 Label1.Caption:='0';
end;


procedure TForm1.Button1Click(Sender: TObject);

var I : integer;

begin
 button1.Enabled:=False;
 Timer1.Enabled:=True;
 I:=StrToInt(Label1.Caption);
 Inc(I);
 Label1.Caption:=IntToStr(I);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 Timer1.Enabled:=False;
 button1.Enabled:=True;
end;

end.


once you clicked the first time, the button will be disabled and you can click as much as you want but it won't "buffer" the click events

--------------------------------------
What You See Is What You Get
 
Hello Again.

Here's maybe a naive idea but it's not put in code yet, so I don't know if this is viable. Hoping the Time function takes that value absolutely, independently if events or procedures are taking place. Ok.
If that is possible, then, take the time of each new event done, if it is within the time intervale of task execution, then goto the end line of Button1.OnClick.

If this doesn't run, well, it could be serve to give ideas, I hope.

Leopardo [hourglass]
 
Whosrdaddy solution is similar to solution i give on 30/05.

Try my solution. That one works fine and it is indipendent from the duration of the slow-process inside it.

You must use timer.
Initial settings for Timer1:
enabled := false
interval := 100 (you may be want to change this depending CPU-clock but i think this is ok for most cases)

Initial settings for Button1 (or any other control):
Tag := 0 (as default)

Code:
procedure TForm1.Button1Click(Sender: TObject);
begin
  if button1.Tag <> 99 then  
    begin
      button1.Tag := 99;
      .........
      (here your process that takes a lot of time ..)
      .........
      timer1.Enabled := true;
    end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled := false;
  button1.Tag := 0;
end;

As far as now, this is the only solution i found.
We all are waiting for a more elegant one .....

Giovanni Caramia
 
Of course you can set Button1.enabled := false if you like:
Code:
procedure TForm1.Button1Click(Sender: TObject);
begin
  if button1.Tag <> 99 then  
    begin
      button1.Tag := 99;
      button1.enabled := false;
      .........
      (here your process that takes a lot of time ..)
      .........
      button1.enabled := true;
      timer1.Enabled := true;
    end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled := false;
  button1.Tag := 0;
end;
 
Try this. I don't have D2, but it is a technique I have used since the good old Windows 3.1 days:
Code:
procedure FlushMouseClicks( AForm:TForm );
var
  tagMSG:MSG;
begin
  repeat until
    PeekMessageA( tagMSG, AForm.Handle, WM_MOUSEFIRST,
                       WM_MOUSELAST, PM_REMOVE ) = False;
end;



procedure TForm1.pbFetchDataClick(Sender: TObject);
begin
  Screen.Cursor := crSQLWait;
  try
    pbFetchData.Enabled := False;
    //
    // ... some long running job ...
    //
  finally
    FlushMouseClicks( Self );
    pbFetchData.Enabled := True;
    Screen.Cursor := crDefault;
  end;
end;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top