Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Can I use a case statement to determine which radio button was selected?


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 8 - Last Post: Dec 4, 2014 11:18 PM Last Post By: Rudy Velthuis (...
tim crouse

Posts: 83
Registered: 2/11/02
Can I use a case statement to determine which radio button was selected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 11:37 AM
Here is a procedure I was trying to use for the on click event for each radio button to determine which button was pressed in a radio group:

procedure TForm1.ChangeFormColour(Sender: TObject);
begin

Case Sender of
RB1 : ShowMessage('The colour is Red');
RB2 : ShowMessage('The colour is Green');
RB3 : ShowMessage('The colour is Blue');
RB4 : ShowMessage('The colour is Yellow');
else ShowMessage('The colour is Unknown!');
end;

I know there is an issue with the data type I am trying to use with case, can someone show me if it is possible?

Thanks
-Tim C.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 11:50 AM   in response to: tim crouse in response to: tim crouse
tim wrote:

Here is a procedure I was trying to use for the on click event for
each radio button to determine which button was pressed in a radio
group:

Use the TRadioGroup.ItemIndex property in the TRadioGroup.OnClick event, eg:

procedure TForm1.TheRadioGroupClick(Sender: TObject);
begin
  case TheRadioGroup.ItemIndex of
    0: ShowMessage('The colour is Red');
    1 : ShowMessage('The colour is Green');
    2 : ShowMessage('The colour is Blue');
    3 : ShowMessage('The colour is Yellow');
  else
    ShowMessage('The colour is Unknown!');
  end;
end;


--
Remy Lebeau (TeamB)
tim crouse

Posts: 83
Registered: 2/11/02
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 11:54 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
OK I see that.

But what if I wanted to find out if an object outside a radio group was pressed? Is there a way to use the sender with a case?

Thanks
Tim C.

Remy Lebeau (TeamB) wrote:
tim wrote:

Here is a procedure I was trying to use for the on click event for
each radio button to determine which button was pressed in a radio
group:

Use the TRadioGroup.ItemIndex property in the TRadioGroup.OnClick event, eg:

procedure TForm1.TheRadioGroupClick(Sender: TObject);
begin
  case TheRadioGroup.ItemIndex of
    0: ShowMessage('The colour is Red');
    1 : ShowMessage('The colour is Green');
    2 : ShowMessage('The colour is Blue');
    3 : ShowMessage('The colour is Yellow');
  else
    ShowMessage('The colour is Unknown!');
  end;
end;


--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Can I use a case statement to determine which radio buttonwasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 3, 2014 12:13 PM   in response to: tim crouse in response to: tim crouse
tim wrote:

But what if I wanted to find out if an object outside a radio
group was pressed? Is there a way to use the sender with a case?

The Sender of the TRadioGroup.OnClick event handler will always be the TRadioGroup.
What you are asking for would only make sense if you have assigned the same
event handler to multiple controls, in which case you have to look at the
Sender to know which control is triggering the event, eg:

procedure TForm1.SomeClickHandler(Sender: TObject);
begin
  if Sender = RadioGroup1 then
  begin
    case RadioGroup1.ItemIndex of
      0: ShowMessage('The colour is Red');
      1 : ShowMessage('The colour is Green');
      2 : ShowMessage('The colour is Blue');
      3 : ShowMessage('The colour is Yellow');
    else
      ShowMessage('The colour is Unknown!');
    end;
  end else
  begin
    //...
  end;
end;


Or:

procedure TForm1.SomeClickHandler(Sender: TObject);
begin
  if Sender is TRadioGroup then
  begin
    case TRadioGroup(Sender).ItemIndex of
      //...
    end;
  end else
  begin
    //...
  end;
end;


--
Remy Lebeau (TeamB)
Rudy Velthuis (...


Posts: 7,731
Registered: 9/22/99
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 5:24 AM   in response to: tim crouse in response to: tim crouse
tim crouse wrote:

OK I see that.

But what if I wanted to find out if an object outside a radio group
was pressed? Is there a way to use the sender with a case?

No. But if you need that, you should rethink your design.

--
Rudy Velthuis http://www.rvelthuis.de

"I doubt, therefore I might be." -- Unknown
tim crouse

Posts: 83
Registered: 2/11/02
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 9:08 AM   in response to: Rudy Velthuis (... in response to: Rudy Velthuis (...
Here is an attempt at using an enum with a case to capture which button is pressed. The capturing of the object sender has not been implemented as i am having trouble getting what I have to compile.
Could someone offer some insight.

unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons;

type
GUIObjectEnum = (RB1, Btn1, Btn2);
TForm1 = class(TForm)
GroupBox1: TGroupBox;
RB1: TRadioButton;
BitBtn1: TBitBtn;
Btn1: TButton;
Btn2: TButton;

private
{ Private declarations }
procedure ChangeFormColour(ButtonPressed : GUIObjectEnum);

public
{ Public declarations }
end;

var
Form1: TForm1;
ButtonPressed : GUIObjectEnum;

implementation

{$R *.dfm}


{ TForm1 }

procedure TForm1.ChangeFormColour(ButtonPressed : GUIObjectEnum);
begin

//This procedure would be used for multiple front panel object
//On-Click Event

//capture sender and assign to enam var at this line
ButtonPressed := RB1; // placed here as a test

Case ButtonPressed of
RB1 : ShowMessage('The colour is Red');
Btn1 : ShowMessage('The colour is Green');
Btn1 : ShowMessage('The colour is Blue');
//RB4 : ShowMessage('The colour is Yellow');
else ShowMessage('The colour is Unknown!');
end;

end;

end.

Rudy Velthuis (TeamB) wrote:
tim crouse wrote:

OK I see that.

But what if I wanted to find out if an object outside a radio group
was pressed? Is there a way to use the sender with a case?

No. But if you need that, you should rethink your design.

--
Rudy Velthuis http://www.rvelthuis.de

"I doubt, therefore I might be." -- Unknown
Rudy Velthuis (...


Posts: 7,731
Registered: 9/22/99
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 11:18 PM   in response to: tim crouse in response to: tim crouse
tim crouse wrote:

procedure TForm1.ChangeFormColour(ButtonPressed : GUIObjectEnum);
begin

//This procedure would be used for multiple front panel object
//On-Click Event

//capture sender and assign to enam var at this line
ButtonPressed := RB1; // placed here as a test

Case ButtonPressed of
RB1 : ShowMessage('The colour is Red');
Btn1 : ShowMessage('The colour is Green');
Btn1 : ShowMessage('The colour is Blue');
//RB4 : ShowMessage('The colour is Yellow');
else ShowMessage('The colour is Unknown!');

You could give each button a different Tag value and read that.

    ButtonPressed := (Sender as TComponent).Tag;
    ChangeFormColour(MyEnum(ButtonPressed));


--
Rudy Velthuis http://www.rvelthuis.de

Canada Bill Jones' Motto: It's morally wrong to allow naive end
users to keep their money.

Peter Below

Posts: 1,227
Registered: 12/16/99
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 9:46 AM   in response to: tim crouse in response to: tim crouse
tim crouse wrote:

OK I see that.

But what if I wanted to find out if an object outside a radio group
was pressed? Is there a way to use the sender with a case?

Well, if you prepare for that it can be done, but the solution is a bit
fragile.
A case statement only allows you to use ordinal types (byte, word,
integer, cardinal, boolean, char, enumerated types) as the case
selector, and the selector values have to be constants known at
compile-time. The Sender parameter, however, is a pointer (object
reference), which is not an ordinal, and its value is not known at
compile time. To get from the object reference to an ordinal you can
use as the case selector you have basically only two options:

1. The Tag property. Each control you can drop on a form descends from
TComponent and inherits the published Tag property. This property is an
integer, so of an ordinal type. You can assign values to the Tag
properties of the controls of interest, either in the designer or in
code when the form is created, and then do something like

case (sender as TControl).Tag of
1: ....;
2: ....;
else
end;

The main problem with this approach (and the reason why I call it
fragile) is that you have no easy way to make sure the tag values are
what you expect them to be, that no two controls are assigned the same
tag, and so on. You can mitigate this problem a bit by assigning the
tag values in code, in a method called from the form's constructor.
That also allows you to use numeric constants with meaningful names
instead of plain numbers. You can even declare an enumerated type that
identifies the controls and assign the ordinal values (obtained via the
Ord function) of the declared members of the type to the Tag properties
(in code). For the case statement you can then cast (sender as
TControl).Tag to the enumerated type, but only after validating that
the tag value is in the range of ordinals of that type, of course.

2. An array of object references.

This can take the form of

case IndexOf(Sender, [button1, button2, button5, checkbox1]) of
0: {code for button 1};
1: {code for button 2};
.....
else
// not one of the expected objects
end;

where

{!
<summary>
IndexOf searches for a given object in an array of objects.</summary>
<returns>
the index of the object (zero-based), or -1, if the object is not
found in the array.</returns>
<param name="aObj">
is the object to look for.</param>
<param name="A">
is the array to look in.</param>
}
function IndexOf(aObj: TObject; const A: array of TObject): integer;
var
I: Integer;
begin
Result := -1;
for I := Low(A) to High(A) do
if A[I] = aObj then begin
Result := I;
Break;
end; {if}
end;

The advantage of this approach is that it requires no additional code
outside the event handler method. The disadvantage is that this is also
a bit fragile, since any change to the object list passed to IndexOf
needs a
matching change to the case list, and if you are not careful those can
get out of sync.


--
Peter Below (TeamB)

tim crouse

Posts: 83
Registered: 2/11/02
Re: Can I use a case statement to determine which radio button wasselected?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2014 4:23 PM   in response to: Peter Below in response to: Peter Below
Very nice explanation, thank you.

Which brings me to the next question....posted under a new thread

How to create a shared event procedure?

Peter Below wrote:
tim crouse wrote:

OK I see that.

But what if I wanted to find out if an object outside a radio group
was pressed? Is there a way to use the sender with a case?

Well, if you prepare for that it can be done, but the solution is a bit
fragile.
A case statement only allows you to use ordinal types (byte, word,
integer, cardinal, boolean, char, enumerated types) as the case
selector, and the selector values have to be constants known at
compile-time. The Sender parameter, however, is a pointer (object
reference), which is not an ordinal, and its value is not known at
compile time. To get from the object reference to an ordinal you can
use as the case selector you have basically only two options:

1. The Tag property. Each control you can drop on a form descends from
TComponent and inherits the published Tag property. This property is an
integer, so of an ordinal type. You can assign values to the Tag
properties of the controls of interest, either in the designer or in
code when the form is created, and then do something like

case (sender as TControl).Tag of
1: ....;
2: ....;
else
end;

The main problem with this approach (and the reason why I call it
fragile) is that you have no easy way to make sure the tag values are
what you expect them to be, that no two controls are assigned the same
tag, and so on. You can mitigate this problem a bit by assigning the
tag values in code, in a method called from the form's constructor.
That also allows you to use numeric constants with meaningful names
instead of plain numbers. You can even declare an enumerated type that
identifies the controls and assign the ordinal values (obtained via the
Ord function) of the declared members of the type to the Tag properties
(in code). For the case statement you can then cast (sender as
TControl).Tag to the enumerated type, but only after validating that
the tag value is in the range of ordinals of that type, of course.

2. An array of object references.

This can take the form of

case IndexOf(Sender, [button1, button2, button5, checkbox1]) of
0: {code for button 1};
1: {code for button 2};
.....
else
// not one of the expected objects
end;

where

{!
<summary>
IndexOf searches for a given object in an array of objects.</summary>
<returns>
the index of the object (zero-based), or -1, if the object is not
found in the array.</returns>
<param name="aObj">
is the object to look for.</param>
<param name="A">
is the array to look in.</param>
}
function IndexOf(aObj: TObject; const A: array of TObject): integer;
var
I: Integer;
begin
Result := -1;
for I := Low(A) to High(A) do
if A[I] = aObj then begin
Result := I;
Break;
end; {if}
end;

The advantage of this approach is that it requires no additional code
outside the event handler method. The disadvantage is that this is also
a bit fragile, since any change to the object list passed to IndexOf
needs a
matching change to the case list, and if you are not careful those can
get out of sync.


--
Peter Below (TeamB)

Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02