-1

I have an application that has 15 Buttons on a form. Each button can be Enabled as required and there are no set configurations so there could dozens of combinations.

To set Btnxxx.Enabled, I am currently using,

procedure TForm1.SetButtons(aStr : String);
  // aStr can be '123456789ABC' for all Enabled
  //          or '123_567__ABC' for all-but 4, 8 and 9 Enabled

begin
  btnInsert.Enabled:=Pos('1',aStr);
  btnVariety.Enabled:=Pos('2',aStr);

This is getting cumbersome and error prone when I add or delete buttons. I tried using Boolean instead of aStr as in

const
  aInsOn = True;
  aInsOff = False;
  aVarOn = True;
  aVarOff = False;

procedure TForm1.SetButtons(InsOnOf, VarOnOff ... for 15 buttons : Boolean);
begin
  btnInsert.Enabled:=InsOnOff;
  btnVariety.Enabled:=VarOnOff;

Calling SetButtons would be

SetButtons(aInsOff, aVarOn, .......);

but that too was less than ideal with huge strings of Boolean settings.

I also tried using the Tag in similar fashion to the aStr example, but it too is error prone.

Does anyone have a pet-idea for doing this? I have not been able to make Actions work due to the unknown combinations of Enabled states of the buttons at any given time.

  • 3
    Actions should work fine. Far and away the best approach. – David Heffernan Jun 11 '14 at 16:37
  • When there are a large number of controls I generally use the component collection and iterate through those to set properties for each. – Gary Mueller Jun 11 '14 at 16:38
  • When there are a large number of controls I generally use the component collection and iterate through those to set properties for each. for example: for idx := 0 to componentCount - 1 do if (components[idx] is TButton) then begin // do whats needed end; The trick for you issue is coming up with a good way to categorize your buttons so that you can act on each category as needed. The above or something similar will help iterating through them. May use the tag to help put each button in a category or use a consistent naming format and get the name of each while in the loop. – Gary Mueller Jun 11 '14 at 16:44
  • 2
    @AlienHeadDiscsL it would be more efficient to put the desired controls into an array/list first, then iterate through that when needed. – Remy Lebeau Jun 11 '14 at 16:52
  • @AlienHeadDiscs Thanks, I had actually tried that some weeks back, it it too was cumbersome when adding or deleting buttons. I think I am looking for something that doesn't exist in a slick-format. :) –  Jun 11 '14 at 18:49
  • @DavidHeffernan Well, I tried for a few hours with Actions and could not get anything to work. From your posts on this site, I am fully aware I do not have your deep knowledge, so if you can give me some sample code I would be grateful. Please see my comment below about the user being in control. –  Jun 11 '14 at 18:52
  • 1
    As David points out, it would be better to control Enabled/Disabled state from actions linked to the buttons. But more to the point: What are you trying to achieve with a "god of buttons method". Having a single method to set all buttons doesn't solve any problems - it just shifts it into an effort of keeping `SetButtons` and all its callers synchronised. Somewhere in your code you have rules that determine "action X should now be enabled/disabled" in such place rather write `ActionX.Enabled := ???;` – Disillusioned Jun 11 '14 at 18:53
  • Start here: http://www.google.com/search?q=delphi+actions – David Heffernan Jun 11 '14 at 18:57
  • What about bit mask in some variable. Each button have own bit representation (in tag . button 1 = 1, button2 = 2, button3 = 4 and so on). Each click set suitable bit (or all bit mask) using bit operators ? – robertw Jun 11 '14 at 19:56
  • @DavidHeffernan: I guess you should add your suggestion as an answer, since it´s by far the best option. – AlexSC Jun 11 '14 at 21:21

3 Answers3

2

This is readily solved with actions. For each button, create an associated action. Assign that action to the button's Action property.

In the OnExecute event handler for the action, do what is necessary to respond to the button being clicked.

In the OnUpdate event handler for the action, set action properties like Caption, Visible, Enabled etc. In your case you need to set Enabled:

(Sender as TAction).Enabled := ...

where ... represents an expression that determines the enabled state of the associated button.

Repeat the process for all other buttons.

As an alternative to this updating strategy, you might set the dynamic properties of all the actions in an OnUpdate handler for the action list.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

You can define a set to control up to 256 buttons.

type
  TButtonId = (BI_INSERT, BI_VARIETY, { ... } BI_FOOBAR);
  TButtonIds = set of TButtonId;

procedure TForm1.SetButtons(EnabledButtons: TButtonIds);
begin
  btnInsert.Enabled := BI_INSERT in EnabledButtons;
  btnVariety.Enabled := BI_VARIETY in EnabledButtons;
  { ... }
  btnFooBar.Enabled := BI_FOOBAR in EnabledButtons;
end;

procedure TForm1.SetToCombination1;
begin
  SetButtons([BI_INSERT, BI_FOOBAR]);
end;

procedure TForm1.SetToCombination2;
begin
  SetButtons([]);
end;

You'd define button states combinations according to your requirement. Now you are very easy to change button states.

stanleyxu2005
  • 8,081
  • 14
  • 59
  • 94
  • Thanks, but the user is in control of the buttons so there could be hundreds of combinations. When the user presses a button a certain combination are available. As they press one of those, a different set becomes available. –  Jun 11 '14 at 18:48
  • I don't understand your objection to this answer, User. Do you think 256 is the maximum number of combinations? That's the limit on the number of buttons; the number of combinations is this 2^256, which is considerably larger. – Rob Kennedy Jun 12 '14 at 06:07
  • @RobKennedy I wrote `SetToCombination1` and `SetToCombination2` as example, but user2175495 thinks there are too many combinations. He wants a `magic` way to handle many combinations with little code (if I understood him correctly). If I were him, I would first analyse the dependencies of these buttons. We cannot avoid to list all possible combinations, before we start to write code. – stanleyxu2005 Jun 12 '14 at 06:23
  • 1
    Maybe you're right, Stanley, but the task of allowing users to select combinations of buttons was never mentioned in the problem statement. I assumed that problem had already been solved. It has nothing to do with this answer; that problem exists no matter which answer is selected. – Rob Kennedy Jun 12 '14 at 06:23
0

I have the same problem in some of my Apps.

With a slightly different code design you can implement that.
I show here a simple code which you can easily expand.

  • 1) Give all your automtic enabled buttons the same name with a number at the end.
  • 2) If you want the state of Button as it is then set it's number to '3'.

procedure TForm1.SetEnaBt(ctrlstr:Ansistring;Count:integer);
var
i:integer;
begin
 for i:=1 to Count do begin
   if ctrlstr[i]='3' then continue;
   with TButton(FindComponent('MyButt'+intToStr(i))) do begin
    if ctrlstr[i]='1' then enabled := true else enabled := false;
   end;
 end;
end;

Call

SetEnaBt(controlStr,255); //='1030312101010101010101....'

or

different groups of buttons with different endings

e.g.

  • Group AEV myButtAEV1 to myButtAEV99
  • Group DEL myButtDEL1 to myButtDEL99
  • Group CRE myButtCRE1 to myButtCRE99

procedure TForm1.SetEnaBt(ctrlstr,nameE:Ansistring;GroupCount:integer);
var
i:integer;
begin
 for i:=1 to GroupCount do begin // set as many Buttons Group has
    if ctrlstr[i]='3' then continue;
   with TButton(FindComponent('MyButt'+nameE+intToStr(i))) do begin
    if ctrlstr[i]='1' then enabled := true else enabled := false;
   end;
 end;
end;

Call

  • SetEnaBt(controlStrAEV,'AEV',88);
  • SetEnaBt(controlStrDEL,'DEL',99);
  • SetEnaBt(controlStrCRE,'CRE',101);

If you want every Button has is own name make a array with all your automatic Buttons Name

Pseudo Code

string array

'btnInsert','btnVariety','...'

procedure TForm1.SetEnaBt(ctrlstr);
var
i:integer;
begin
 for i:=1 to ArrayStrCount do begin // set as many Buttons Group has
   with TButton(FindComponent(arrayStr[i-1])) do begin
    if ctrlstr[i]='1' then enabled := true else enabled := false;
   end;
 end;
end;

It is easy to maintain.
If you delete a button then set his
according ctrlstr[number] to '2' and the according arraystr[number]='del'.

test it like

string array
'btnInsert','del','btndoSome','....'
[...]

for i:=1 to ArrayStrCount do begin
if (ctrlstr[i]='2') OR (ctrlstr[i]='3') OR (arraystr[i-1]='del') then continue;
[...]

If you want only set the first 10 Buttons and ignore the other 200.
set according controlStr[number] to '4'

controlStr == 1310101010410101010101010101 .....

[...]

for i:=1 to ArrayStrCount do begin
if ctrlstr[i]='4' then break;
if (ctrlstr[i]='2') OR (ctrlstr[i]='3') OR (arraystr[i-1]='del') then continue;
[...]
moskito-x
  • 11,832
  • 5
  • 47
  • 60