Getting the name of newly created components at run time - delphi

Essentially, I want a user to add comments in the form of labels. I have implemented this no problem, but I want the user to be able to delete the newly created labels.
comment := TLabel.Create(Self);
comment.Parent := Form1;
I want to add Labels during runtime, and then fill a combobox or a stringgrid or something similar with the name or any sort of a reference to that label, so that the user can then delete that label.
How would I get the name of the newly created label for a reference ?
Thanks for any help.

Components that you create yourself don't have a Name assigned unless you explicitly assign one yourself. It is the IDE that synthesizes a Name when you drop a component on the form at design-time.
You can just assign whatever Name you feel like, as long as it's a valid component name (unused, no spaces, and so on), and then the component can be found via its Owner.FindComponent() method, if you don't keep track of the component yourself. Otherwise, put the component into your own list/array so you can find it later.

The name of a component can be read from its Name property:
comment.Name
You can write to that property to give the component a name that is amenable to showing to users. You'll want to do that when you create a new component dynamically because it won't have a name until you name it.
There's no need for you to use the Name property if you don't wish to. You can use naming of your own choice. For instance you may wish to use names that contain spaces. Or not be constrained from using names that are already in use by the static controls. Hold the components in a dictionary with the name as the key and the component as the value. My advice is that you go down this second path.

Related

Cannot assign to a read only property

I have a form which has a TDBLookupComboBox on it.
The TDBLookupComboBox is displaying a list of records from within a database table.
At the point of the forms OnShow event I would like the TDBLookupComboBox to already display one of the strings in the list.
I have done this so far...
procedure TfrmMain.FormShow(Sender: TObject);
begin
dblucbox.Text := Username;
end
Username is a string for one of the records already in the list.
At the point of compiling, I get an error saying
Cannot assign to a read only property
I'm a bit stuck with this so any help would be appreciated.
Don't try to modify the Text property, instead if you want set the TDbLookUpComboBox in a particular item you must use the the KeyValue property which will try to locate the record in the underlying TDataSet.
So you if you have Key Value of the user you can use something like this
dblucbox.KeyValue := UserId;
Otherwise you can use the Locate method of the underlying TDataSet, to find the match and the LookUp control will be refreshed automatically
You're going about this backwards. To be more precise, the DBLookupCombo is reflecting the state of the database table. So you want to be manipulating the table, not the combobox.
In other words, the OnShow event needs to open the table that's the object of the DBLookupCombo (if it's not already open) and then position the current record to be the one you want displayed as the default.

Possibility to write a code to put auto names for controls using different rules in Orbeon Form Builder

We all know that when we create new control in FB it gives its name control-1. When we create the next control it give its name control-2 an so on. Is it possible to write a rule for giving names to controls? For instance: For specific column in grid, column with name A, give to all controls in this column name which starts with A_ suffix?
As a form author, you can change the name of a control after you add it in Form Builder. However, if you want to change the default naming scheme, you would have to change code in Orbeon Forms. Currently, this is done with controlName(nextId(doc, "control")) in ToolboxOps.scala.

Searching through form & Uses

We are creating a component and want to mimic the concept behind Designer.GetComponentNames, where as we give can obtain a list of the available components on the form or any form in the uses. We haven't been able to get to the root of GetComponentNames. Any input would be much appreciated.
LE: Actually I take that back. I need this from the design time aspect.
Runtime? You have the Vcl.Forms.TScreen.Forms array for all the displayed forms, and you have Vcl.Forms.Application.Components containing all your forms IIRC. Then, each form has a Components array.
If I understand the first part of your question, you want to get a list of components owned by a form (by name) at designtime.
As background, I have a non-visual component (Call it TColorEdits.) that manages the colors of selected TWinControls on a form at runtime. This component has a TStrings property that contains the names of selected TWinControls on the form. The names of TWinControls to be managed may be selected at designtime using a dialog (dlgEditColors) that contains a couple listboxes, one of which is named DstList and shows all TWinControls available for management by TColorEdits.
So, here is some (simplified) code I use to get the names of TWinControls on a form at designtime and load the TWinControl names into DstList.
{ Load names of TWinControls owned by a form into TListBox DstList }
for i := 0 to TColorEdits(GetComponent(0)).Owner.ComponentCount - 1 do
if ((TColorEdits(GetComponent(0)).Owner.Components[i] is TWinControl) then
dlgEditColors.DstList.Items.Add(TColorEdits(GetComponent(0)).Owner.Components[i].Name);
You should be able to adjust the above code as part of a custom property editor for your component. Hope this helps with the first part of your question.

Is there a ComboBox that has Items like a TcxRadioGroup?

The TcxRadioGroup component of DevExpress has a very nice way to specify items. You can specify a Caption and a Value (and a Tag) for each TcxRadioGroupItem.
The TcxComboBox and the normal TComboBox of Delphi on the other hand use TStrings to store its items.
While TStrings can have a Name and an Object, there is no easy way to hook up a name and a value using the form designer of the Delphi IDE.
Is there a ComboBox control (preferably from DevExpress) that allows to visually design its items with a Caption and a Value?
PS: I'm not looking for a DB aware control.
Try a TcxImageComboBox. See here - you don't have to assign images despite the name. You can also edit the items visually.
(I use it as cell editor in cxGrids because of the separation Description/Value.)
Raize Components have TRzComboBox which introduces a Values property as an addition to the existing Items.
ESBPCS for VCL has an enhanced Lookup ComboBox. It stores 2 Lists, the ones normally in TCombobox's Items as well as the new Values list. These two StringLists are in a 1-1 relationship. Use AsItem to retrieve the string currently displayed and AsValue to retrieve the "related" string from Values.
Use a standard Delphi TComboBox, it can store a string (for visualization, and an object of any TObject descendant that you implement yourself, i.e you can store anything associated to a string in the dropdown).

What is the purpose of the 'Tag' property of Delphi VCL components?

Is there any specific purpose for the 'Tag' property of Delphi VCL components?
I have Googled a few examples using it as, for example, a 'color' property or using the value as a pointer address, but is it 'good practice' to use it, or is it considered 'bad practice' as it ties the program logic to the UI?
The "tag" property is there as a "cargo container" for whatever you might want to do with it.
Something it's often used for is in event handlers when you have a lot of similar components sharing one event handler. The event handler can find its caller and then query its tag value to get some more information about what it's supposed to be acting on.
EDIT:
Example: A calculator app might tag the number buttons with their respective numbers... silly and incomplete example, but you get the idea. The event handler could then pull the number to add into the display and accumulator right out of the tag instead of having to go figure out which button is meant to do what.
It is a place to add a piece of information to any component, even if you don't have the source for that component. It should be used carefully, because you can use it for only one purpose per component. For that reason Libraries should never use it.
I have some fundamental problems with the Tag property.
Well not exactly this property itself because it works as intended.
In general I consider using any universal/general/multi-purpose variables as a 'bad practice'.
They can be useful during debugging but are very harmful in production/mission critical environment.
They reduce code readability and understandability because nobody knows what a 'Tag' named attribute or property does. Of course you know why you are using this variable. But sooner or later you will forget (I know you will) and relying on this value makes anything more complicated.
This is why we should properly name every variable and property to help us understand what the code does.
Using Tag property is just a workaround/shortcut to avoid implementing understandable and well written code.
This is the PRACTICE and it is addictive.
Next time you need to store a new integer value bound to a component you will use the Tag property without considering any other way to store the desired values.
And storing a pointer in Tag property is a horrible idea: you have to cast this value every time you debug pointers.
Tell me: how many times did you find yourself in a situation where you wanted to store a new value in the Tag property but you realized this property is already used for a different purpose (if only there would be a 'Tag2' property in every component...).
As others have said, it's a place to put anything. Typically this comes in handy when associating two objects via an object reference or pointer. The tag happens to be perfectly sized to hold a pointer, so if you need to, say, keep an object tied to an item in a listbox, it becomes pretty straightforward.
Also it can be used for grouping purposes, say you'd want to access all components with a specific tag value, regardless of the component's type.
It's great! A freebie. I use it all the time to store one additional piece of information associated with the object.
Often I store a pointer to an associated data structure, or sometimes an integer which may be an index into some other array.
You can use it as a counter for times the object is accessed, or whatever.
The only downside is if your program uses lots of memory and you have millions of objects, those 4 bytes for each tag add up, especially if you're not using it. In that case, for your most prolific object type, you may want to create your own version without the tag.
You have 2 buttons on your form, on one you set the Tag = 1, and the other one Tag = 2. Now you assign the same OnClick event to both buttons and writhe the code like this:
procedure TForm28.Button1Click(Sender: TObject);
begin
case (Sender as TButton).Tag of
1: Caption := 'you pressed button 1';
2: Caption := 'you pressed button 2';
end;
end;
or more compact:
procedure TForm28.Button1Click(Sender: TObject);
begin
Caption := 'you pressed button ' + IntToStr((Sender as TButton).Tag);
end;
Basically,Tag will let you identify what control fired the event. Think if you have a form with dynamically created buttons... a list with users from the database, and on each record you put a button "Delete User". In this situation you can't create an event for each button, you will create one event that will assigned to all the buttons... and you can put in the Tag the userid for example. That way when you implement the event to handle all the buttons, you'll know what user to delete.
I Use tags all the time.
here are some examples;
a simple sample: you have a notebook (Like a pagecontroll without tabs)
so you can define buttons as tabs and write
NoteBook.ActivePage := TButton(Sender).Tag;
A more complicated sample;
an integer can hold 16 bitwise bolleans;
I can then check the senders up to 16 conditions to decide how to continue the pricedure
If (BitCheck (Bit2,TButton(sender).tag=True) And BitCheck(bit12,TButton(Sender).Tag=False) Then
Begin
end;
If (BitCheck (Bit9,TButton(sender).tag=True) Or BitCheck(bit14,TButton(Sender).Tag=True) Then
Begin
end;
You Get the idea

Resources