Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a variable if any action is done (in Delphi)?

Tags:

delphi

I need to somehow implement this in Delphi 2009:

The user clicks on button 2. If the user's very last action was clicking on button 1, then I want to do one thing, but if the user's very last action was anything else, I want to do another thing.

Obviously, I set up a boolean variable: UserClickedOnButton1 and set it to true when button 1 is clicked on, and I test that variable in the OnButtonClick event for Button 2.

My question is how do I set that to false whenever anything else is done by the user before clicking on button 2. (e.g. Mouse press, key press, arrow keys, switch to another program, or anything else).

... or is there a simpler way to do this that I am overlooking.

like image 843
lkessler Avatar asked Dec 17 '22 11:12

lkessler


2 Answers

The code below seems to work (D7), but please check this for your specific situation.

type
  TButton = class(StdCtrls.TButton)
  private
    FClickedLast: Boolean;
    FNextButton: TButton;
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    procedure Click; override;
    property ClickedLast: Boolean read FClickedLast write FClickedLast;
    property NextButton: TButton write FNextButton;
  end;

  TForm1 = class(TForm)

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.NextButton := Button2;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Button1.ClickedLast then
    Caption := Caption + ' +'
  else
    Caption := Caption + ' -';
  Button1.ClickedLast := False;
end;

{ TButton }

procedure TButton.Click;
begin
  inherited Click;
  if (FNextButton <> nil) and Focused then
    FClickedLast := True;
end;

procedure TButton.WndProc(var Message: TMessage);
begin
  if (FNextButton <> nil) and not (csDestroying in ComponentState) then
    case Message.Msg of
      CM_CANCELMODE,
      WM_KEYFIRST..WM_KEYLAST:
        FClickedLast := False;
      WM_KILLFOCUS:
        if TWMKillFocus(Message).FocusedWnd <> FNextButton.Handle then
          FClickedLast := False;
    end;
  inherited WndProc(Message);
end;

Explanation:

  • CM_CANCELMODE handles mouse clicks anywhere not resulting in changing focus,
  • WM_KEY* handles all key events, but also switching to another application (there is a WM_SYSKEYDOWN, otherwise WM_KILLFOCUS takes care),
  • WM_KILLFOCUS handles everything else.
like image 50
NGLN Avatar answered Jan 06 '23 09:01

NGLN


From what I think; It's not really possible unless you're willing to go and track all (or at least all possibly unwanted) of events with logic.

A key-press (Tab?) can still be valid to move on to the next button and click it; a mouse-down event, obviously is good if it's on the second button, otherwise it's not. You'd probably want to check if the 'first button is clicked' before executing a whole bunch of logic to slow down every keypress/mousedown/lostfocus event in your application.

An idea could be to use a timer, but this doesn't prevent the user from 'quickly' doing something else.

Edt1: If all other actions that are 'illegal' are actually doing something, perhaps a lostfocus event on the first button could be a start?

like image 22
PtPazuzu Avatar answered Jan 06 '23 10:01

PtPazuzu