Recent

Author Topic: Access Component by Name  (Read 5180 times)

Newmann

  • Jr. Member
  • **
  • Posts: 65
Access Component by Name
« on: September 06, 2013, 01:18:27 am »
Hi guys,
I don't really know how to ask this question - but how do I access a component if I can only calculate the name at runtime?

Here's my problem - I created a calendar (can't use the standard IDE one - not touch screen friendly enough) out of a series of TShape and TLabel components (6x rows of 7x items), lined up and positioned in a rectangle.

I added an OnClick event to each one of the labels to a procedure called "HighlightSelected(Sender:TObject)", and each one of the labels name matches the name of the shapes with only the first three letters being different - basically this groups the item by name so that I know exactly which is which.

Function calls specify the name as follows (in this case its for label "lbl_a1"):
Code: [Select]
HighlightSelected(lbl_a1);
Each function call has the appropriate component name in there - if I add anything else (like "self") in there, it doesn't work at all.

Items are named, and grouped as follow:
Quote
lbl_a1 => label component
shp_a1 => shape component

Row1: a1, a2,a3...a7
Row2: b1,b2,b3...b7
.
.
.
Row6: f1, f2, f3...f7


The idea is simple - when the user touches the label to select a date, I can read from the "Sender as TLabel" command what the caption property is to get the selected date, but now I want to highlight the selected date by changing the shape behind its color from clWhite to clYellow.

Right now I have 42 if statements like this:
Code: [Select]
if sender = lbl_a1 then shp_a1.Brush.Color := clYellow;
if sender = lbl_a2 then shp_a2.Brush.Color := clYellow;
if sender = lbl_a3 then shp_a3.Brush.Color := clYellow;
if sender = lbl_a4 then shp_a4.Brush.Color := clYellow;
if sender = lbl_a5 then shp_a5.Brush.Color := clYellow;
if sender = lbl_a6 then shp_a6.Brush.Color := clYellow;
if sender = lbl_a7 then shp_a7.Brush.Color := clYellow;



Right now it obviously works fine, but I was wondering if there isn't a more efficient method of doing this?
(especially because the component names are similar)

I fiddled around with the following as well - might give you a better idea of what I'm after - but obviously I couldn't get it to work right:

Code: [Select]
HighlightSelected(Sender:TObject);
var
   senderName : String;

begin
   senderName := 'shp_' + Copy(sender.UnitName, 5, 2);
   with FindComponent(senderName) do Brush.Color := clYellow;
end;


Like I said - the long way is working, but obviously its not very efficient - I was just wondering if I could optimize it a bit? Any ideas or suggestions will be greatly appreciated, thanks! ;)
Lazarus 1.0.14
FPC 2.6.0
Win7 Pro 64bit/Win XP Pro 32bit

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Access Component by Name
« Reply #1 on: September 06, 2013, 01:33:02 am »
actually it depends what you mean efficient, efficient as in execution speed? efficient as in clear intention on what it does? efficient as in minimize the controls created?

Speed wise the code you have with the ifs will be faster I think probably a case might make it a bit faster but not something measurable I think. The intention of the code is also clear with the Ifs.

As for replacing the if chain with a search loop all controls that have the same parents can be found in the components controls property you can simple write something like
Code: [Select]
Function FindControl(constRef aName:string):Tcontrol;
var
  vCntr : Integer;
begin
  Result := nil;
  for vCntr := 0 to ControlCount -1 do begin
    if controls[vCntr].name = aName then begin
      Result := controls[vCntr];
      Break;
    end;
  end;
end;
or use the findChildControls method of TwinControl descendants that does the same thing.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

 

TinyPortal © 2005-2018