Bart Verbakel 3 Posted October 18, 2023 Hello all, I have a question, but i don't know exactly how to explain the problem... Is it possible to use "dynamic" control names to set their properties? For example: I have a form with 5 buttons (Button1, Button2...Button5) Instead of using following code: Button1.Enabled:=True Button2.Enabled:=True Button3Enabled:=True Button4.Enabled:=True Button5.Enabled:=True I want to use something like: for k:=1 to to 5 do (Edit-k-).enabled=True; I hope you understand my question :) With kind regards, Bart Share this post Link to post
Roger Cigol 103 Posted October 18, 2023 (edited) In C++ this is easy to do, provided you ensure that the five buttons are all in order in the header file for the form class. You then declare a pointer to the first button and then iterate through the series of buttons, incrementing the pointer each time until you reach the last button. Not sure of the equivalent in Delphi but I suspect there is one! I use this technique a lot. I listen to (and value) my learned colleagues advice here. It is correct. I have ran into this packing problem with structures / classes. This approach is "dodgy". As recommended below : need to create an array of pointers and iterate through this. Thanks to Remy and Sherlock for the benefit of their expertise. Edited October 19, 2023 by Roger Cigol Less than ideal advice ! 1 Share this post Link to post
Fr0sT.Brutal 900 Posted October 18, 2023 (edited) FindComponent Or better set array of these buttons at form create and then loop through the array Edited October 18, 2023 by Fr0sT.Brutal 4 Share this post Link to post
DelphiUdIT 178 Posted October 18, 2023 (edited) One of the various ways is to "cycle" within the controls of the parent component: to identify the affected control you could give a value to the tag property during the design phase (for example from 1000 to the first Button, 1001 to the second, etc. ..), then this will be the code assuming you are looping through the controls of a Form (Form1): var CB: TControl; for var i := 0 to Form1.ControlCount-1 do begin CB := Form1.Controls[i]; if (CB is TButton) and ((CB as TButton).Tag > 1000) then begin (CB as TButton).Enabled := True; end; end; Edited October 18, 2023 by DelphiUdIT Share this post Link to post
Remy Lebeau 1405 Posted October 18, 2023 (edited) 1 hour ago, Roger Cigol said: In C++ this is easy to do, provided you ensure that the five buttons are all in order in the header file for the form class. You then declare a pointer to the first button and then iterate through the series of buttons, incrementing the pointer each time until you reach the last button. Not sure of the equivalent in Delphi but I suspect there is one! I use this technique a lot. Don't do that! You are invoking undefined behavior. You can only iterate using a pointer like that if the values are in an array, Otherwise, you can't be sure the compiler is not adding padding between them inside the class. If you want to use a pointer to iterate the members, you have to put them into an array first and iterate that instead. Edited October 18, 2023 by Remy Lebeau 1 Share this post Link to post
Remy Lebeau 1405 Posted October 18, 2023 53 minutes ago, DelphiUdIT said: One of the various ways is to "cycle" within the controls of the parent component That "works" but may be overkill, as you would potentially be iterating through a lot of other controls that you are not interested in. Share this post Link to post
Kas Ob. 121 Posted October 18, 2023 1 hour ago, Bart Verbakel said: Is it possible to use "dynamic" control names to set their properties? I do use lists, i create a list lets, say i want a bunch of controls to be enabled or disabled when a specific value is right/wrong in an edit, register these controls once and use helper function or any other method you like, to enable or disable them, lists are great for grouping. you can hide and show also. 1 Share this post Link to post
Pat Foley 51 Posted October 18, 2023 So inside an application with many forms and Controls you could build a list of Controls addresses by searching by form name and then component name and use list later with getparentform is easy to bringtofront and show needed controls. Or realizing the list when custom controls or even standard controls are loaded at runtime. 1 Share this post Link to post
Uwe Raabe 2059 Posted October 18, 2023 First of all, keeping the default names for the buttons has never been best practice. While suggesting to have descriptive names for the buttons, this nevertheless is another way to iterate over any group of buttons: for var btn in [Button1, Button2, Button3, Button4, Button5] do btn.Enabled := True; And, no, you can't write [Button1..Button5] here. 7 Share this post Link to post
Pat Foley 51 Posted October 18, 2023 38 minutes ago, Uwe Raabe said: And, no, you can't write [Button1..Button5] here Put in a FlowPanel to make visual collection and Buttons are listed as FlowPanel.Controls. 🚋 42 minutes ago, Uwe Raabe said: While suggesting to have descriptive names for the buttons Here's sample based on Cantu's 10.4 guide. Button renamed Karma operates two checkboxes with descriptive event handlers. Type TKarma = 0..10; const KarmaRatingCutoff = 7; //allow good Karma when good most of the time was 8 var Goody: Boolean = False; KarmaRange: TKarma = High(TKarma); KarmaNow: TKarma = 0; procedure TForm21.KarmaChange(Sender: TObject); begin Screen.Cursor := crAppStart; //calm the user with phone like spinner Karma.OnClick := nil; Bad.OnMouseDown := nil; Good.OnMouseDown := nil; //snuff the event handlers Karma.Enabled := False; Bad.Enabled := False; Good.Enabled := False; //prevent user input KarmaNow := Random(KarmaRange); Goody := KarmaNow > KarmaRatingCutoff; //direct assignment no ifs + Ranged to conserve the KarmaBase sleep(7); // Good.Checked := Goody; Bad.Checked := not Goody; if Goody then Karma.Hint := 'Yaa' else Karma.Hint := 'Yuch'; Karma.ShowHint := True; Screen.Cursor := crDefault; // Bad.OnMouseDown := BadmdEvent; // Good.OnMouseDown := GoodmouseEvent; restore one at a time to find bad actors Karma.onClick := KarmaChange; Karma.Enabled := True; end; Share this post Link to post
DelphiUdIT 178 Posted October 18, 2023 3 hours ago, Remy Lebeau said: That "works" but may be overkill, as you would potentially be iterating through a lot of other controls that you are not interested in. You are right. But I normally use it with Panels, GroupBoxs, or such containers and inside them I put only few controls. I use it for example to enable controls with various login and disable them after logout, I found it very simple, and manipulating the tag value only (1K = Login Level 1, 2K = Login Level 2, etc ...). If I need to modify only some properties, I don't need to know the class of the controls ... eg. Enabled, Visible are common to all TControls so not needs explicit use of "(CB as TButton)" ... or "IF (CB is TButton)" But like some others wrote there are more methods, surely better than this. N.B.: very often I create a lot of controls at runtime, and in that way assigning a tag value is enough. I don't need list or static enumeration. Share this post Link to post
dummzeuch 1506 Posted October 19, 2023 (edited) Another option would be to have a procedure like this: procedure TButtons_SetEnabled(const _Buttons: array of TButton; _Value: Boolean); var btn: TButton; begin for btn in _Buttons do btn.Enabled := _Value; end; And call it like this: TButtons_SetEnabled([Button1, Button2, Button3], True); Not much of a typing saver, but not as repetitive. Edit: Just noticed that Uwe already suggested a similar approach. Edited October 19, 2023 by dummzeuch 1 Share this post Link to post
JohnLM 14 Posted October 19, 2023 (edited) 22 hours ago, Uwe Raabe said: First of all, keeping the default names for the buttons has never been best practice. While suggesting to have descriptive names for the buttons, this nevertheless is another way to iterate over any group of buttons: for var btn in [Button1, Button2, Button3, Button4, Button5] do btn.Enabled := True; And, no, you can't write [Button1..Button5] here. I learned something new. This works as described..,, minimal code and easy to follow. I added an addition in case I were to want a toggle type set of on/off controls for certain situations, but slightly more code: for var btn in [Button1, Button2, Button3, Button4, button5] do if btn.Enabled = true then btn.Enabled:=false else btn.Enabled:=true; Edited October 19, 2023 by JohnLM Share this post Link to post
Uwe Raabe 2059 Posted October 19, 2023 That could even be simplified to: for var btn in [Button1, Button2, Button3, Button4, button5] do btn.Enabled := not btn.Enabled; 1 Share this post Link to post
JohnLM 14 Posted October 19, 2023 Ah, I knew about the 'not' and used it in similar situations but not used often enough to remember exactly in this case. Share this post Link to post
Bart Verbakel 3 Posted October 23, 2023 Thank you for al the replies. I have to do some more investigation to find out which solution is the best for me and write a simple application to check its behaviour. Bart Share this post Link to post
David Schwartz 427 Posted October 25, 2023 (edited) If they are indeed "dynamic" controls -- ie, they're defined at run-time -- then the best way is to create an array of T or a TList<T> to contain them. If there are groups of them, then make a class or put them on a panel and make a list of the panels and iterate over the (known) controls on each panel. I find myself doing this relatively often for both components put on the form at design time as well as at run-time. Edited October 25, 2023 by David Schwartz Share this post Link to post
Bart Verbakel 3 Posted October 25, 2023 (edited) No,these are not dynamic controls that are defined at runtime. Maybe I choosed the wrong words for this topic. The controls are defined at the design phase, I want to replace the "static" code Edit1.text:='ABCD' replaced by another code where the '1' is a variable. so I can use some code like: var sName:Array[1..10] of string for k:=1 to 10 do sName[k]:=Edit[k].text; I am now checking which solution mentioned above is the best for me Edited October 25, 2023 by Bart Verbakel Share this post Link to post
Fr0sT.Brutal 900 Posted October 30, 2023 There are even options to wrap some or even any property assignments into one container object and write something like ButtonsList.Enabled := True Share this post Link to post