Fuzail
Fuzail

Reputation: 81

How to make the same button run different code everytime it is clicked?

I am currently doing a school project, I am making a Credit Card machine. I need the 'Enter Button' to run different code when it is clicked. The first click must get the card number from an edit ps... (I clear the edit once the card number has been retrieved), and the second click must get the pin from the same edit. How would I do this?

procedure TfrmMainMenu.btbtnEnterClick(Sender: TObject);

var

 sCvv,sPin:string;

begin

iCount2:=0;

sCardNumber:=lbledtCardInfo.Text;

if (Length(sCardNumber)<>16) AND (iCount2=0) then

 begin

    ShowMessage('Card number has to 16 digits,please try again!!');

  end

  else

  begin

  Inc(iCount2);

  lbledtCardInfo.clear;

  lbledtCardInfo.EditLabel.Caption:='Enter Pin' ;

  btbtnEnter.Enabled:=false;

  end; //if

  if iCount2=2 then

  begin

     btbtnEnter.Enabled:=true;

    sPin:=lbledtCardInfo.Text;

     ShowMessage(sPin);//returns a blank

  end;

Upvotes: 2

Views: 870

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595827

You could try to do everything in a single event handler. There are several different ways to handle that. However, a different solution would be to use separate event handlers for each task, and then each task can assign a new handler for the next click to perform, eg:

procedure TfrmMainMenu.FormCreate(Sender: TObject);
begin
  // you can set this at design-time if desired...
  btbtnEnter.OnClick := GetCCNumber;
end;

procedure TfrmMainMenu.GetCCNumber(Sender: TObject);
begin
  sCardNumber := lbledtCardInfo.Text;
  if Length(sCardNumber) <> 16 then
  begin
    ShowMessage('Card number has to 16 digits,please try again!!');
    Exit;
  end;
  lbledtCardInfo.Clear;
  lbledtCardInfo.EditLabel.Caption := 'Enter Pin' ;
  btbtnEnter.OnClick := GetCCPin;
end;

procedure TfrmMainMenu.GetCCPin(Sender: TObject);
var
  sPin: string;
begin
  sPin := lbledtCardInfo.Text;
  if Length(sPin) <> 4 then
  begin
    ShowMessage('Card Pin has to 4 digits,please try again!!');
    Exit;
  end;
  ShowMessage(sPin);
  ...
  lbledtCardInfo.Clear;
  lbledtCardInfo.EditLabel.Caption := 'Enter Number' ;
  btbtnEnter.OnClick := GetCCNumber;
end;

A variation of this would be to create multiple buttons that overlap each other in the UI, and then you can toggle their Visible property back and forth as needed, eg:

procedure TfrmMainMenu.FormCreate(Sender: TObject);
begin
  // you can set this at design-time if desired...
  btbtnCCPinEnter.Visible := False;
  btbtnCCNumEnter.Visible := True;
end;

procedure TfrmMainMenu.btbtnCCNumEnterClick(Sender: TObject);
begin
  sCardNumber := lbledtCardInfo.Text;
  if Length(sCardNumber) <> 16 then
  begin
    ShowMessage('Card number has to 16 digits,please try again!!');
    Exit;
  end;
  lbledtCardInfo.Clear;
  lbledtCardInfo.EditLabel.Caption := 'Enter Pin' ;
  btbtnCCNumEnter.Visible := False;
  btbtnCCPinEnter.Visible := True;
end;

procedure TfrmMainMenu.btbtnCCPinEnterClick(Sender: TObject);
var
  sPin: string;
begin
  sPin := lbledtCardInfo.Text;
  if Length(sPin) <> 4 then
  begin
    ShowMessage('Card Pin has to 4 digits,please try again!!');
    Exit;
  end;
  ShowMessage(sPin);
  ...
  lbledtCardInfo.Clear;
  lbledtCardInfo.EditLabel.Caption := 'Enter Number' ;
  btbtnCCPinEnter.Visible := False;
  btbtnCCNumEnter.Visible := True;
end;

Upvotes: 2

Andreas Rejbrand
Andreas Rejbrand

Reputation: 108948

Notice that you test iCount2 = 0 immediately after setting iCount2 := 0. Thus, that test will always be True. Furthermore, the later test iCount2 = 2 will always be False because the value starts at 0 and you only have one Inc in between.

Instead try the following.

Add two string fields FCardNumber and FPin to your form class:

private
  FCardNumber: string;
  FPin: string;

Also create an enumerated type TEntryStage = (esCardNumber, esPin) and add a field of this type. This will make your code look like this:

private
type
  TEntryStage = (esCardNumber, esPin);
var
  FCardNumber: string;
  FPin: string;
  FEntryStage: TEntryStage;

In Delphi, class fields (class member variables) are always initialized, so FEntryStage will be esCardNumber (=TEntryStage(0)) when the form is newly created.

Add a TLabeledEdit (I see you use those) and a TButton; name them eInput and btnNext, respectively. Let the labeled edit's caption be Card number: and the caption of the button be Next.

Now add the following OnClick handler to the button:

procedure TForm1.btnNextClick(Sender: TObject);
begin

  case FEntryStage of
    esCardNumber:
      begin

        // Save card number
        FCardNumber := eInput.Text;

        // Prepare for the next stage
        eInput.Clear;
        eInput.EditLabel.Caption := 'Pin:';

        FEntryStage := esPin;

      end;

    esPin:
      begin

        // Save pin
        FPin := eInput.Text;

        // Just do something with the data
        ShowMessageFmt('Card number: %s'#13#10'Pin: %s', [FCardNumber, FPin]);

      end;
  end;

end;

You might notice that you cannot trigger the Next button using Enter, which is very annoying. To fix this, do

procedure TForm1.eInputEnter(Sender: TObject);
begin
  btnNext.Default := True;
end;

procedure TForm1.eInputExit(Sender: TObject);
begin
  btnNext.Default := False;
end;

Much better!

Upvotes: 1

Related Questions