Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

changing properties of multiple components... 3

Status
Not open for further replies.

pierrotsc

Programmer
Nov 25, 2007
358
US
I have a lot of spinedit and was wondering if it possible to modify their properties a better way than i am doing.

right now i have:
square001.readonly := true;
....
Square100.readonly := true;

So i have 100 lines..Anyway to have a smarter method to do that?
Thanks.
P
 
This is not an officially sanctioned way of doing this, as it has no gaurantees of working in subsequent versions of Delphi.

As long as the components are declared sequentially in the class declaration, you can create an array of TSpinedit type, along with a pointer type to it. Assign the pointer to the address of the first Spinedit, and then you can iterate through each of the spinedits using a for loop as follows:

Code:
...
type
  TSPinEdArr = Array[1..3] of TSpinEdit;
  PSpinEdArr = ^TSpinEdArr;

  TForm1 = class(TForm)
    SpinEdit1: TSpinEdit;
    SpinEdit2: TSpinEdit;
    SpinEdit3: TSpinEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  TestArr : PSpinEdArr;
  I : Integer;
begin
  TestArr := @SpinEdit1;
  for I := 1 to 3 do
    TestArr[I].Value := 50;
end;
...

As I stated initially, this is a HACK, and is not reccomended by the hard core delphi professionals, but it does work on all versions up to XE2. If Delphi changes the way it sets up the Memory image for classes in a future version for classes, then all bets are off and this could cause read and write faults.
 
You could also iterate through the components of the form, looking for spinedits...

For I := 0 to Form.ComponentCount - 1 do
begin
(FindComponent('square'+inttoStr(I)) as Tspinedit).readonly := true;
end;

Of course if you actually named then square001, as opposed to square1, then you going to have to pad I with the extra zeros.
 
If you're looking to act on all like controls, I'd just iterate the component list and look for the type you're interested in. For example, this sets the text on all TEdits of the form.

Code:
procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  for i := 0 to (ComponentCount - 1) do
    if Components[i] is TEdit then
      TEdit(Components[i]).Text := 'Test Test';
end;

I'd probably do the array if I were dynamically creating all the components instead of putting them in the form editor.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Having (near or over) 100 spinedits on a form is a design-error in my book...
 
Thanks guys, i am going to try glen999's method. The form in question only have spinedits...
P
 
Guys, thank you very much..it make my code a lot lighter.
Now I have this code 100 times when i populate my spinedit from the database.
can i do it on a loop too instead of having 100 lines?
Square001.Value :=
EmbeddedDM.nxTable_trials.FieldByName('Trial_square001').AsFloat;

.....

Square101.Value :=
EmbeddedDM.nxTable_trials.FieldByName('Trial_square101').AsFloat;

thanks
P
 
If the fields are all sequential, then use Fields instead of FieldByName...
 
BTW, if you have a table with 100 columns all essentially for the same type of data, then you really need to think about redesigning the database schema.

That type of information should be separated into a another table, that has a foreign key reference back to the parent table.
 
@ Majumbo:

I tried the fields but i cannot make it work:
for i := 0 to (ComponentCount - 1) do
if Components is TSpinEdit then
begin
TSpinEdit(Components).Value :=
EmbeddedDM.nxTable_trials.Fields.Fields[i + 8].AsFloat;
end;

I think the problem is that although i have 101 tspinedit, i have more components on the form so it triggers an error with the fields array.

Next, i am very new to database schema so i'd love to learn more about redesigning my schema. I do indeed have 101 colums of a float type of data.
Thanks.
P
 
You are not going to want to use I to reference the field, since there are other controls on the form..

Simply use another variable,
Code:
var
   I, J: Integer;
begin
   ...
   J := 7;//not a big fan of having magic numbers but....
   ...
   begin
      TSpinEdit(Components[i]).Value :=
        EmbeddedDM.nxTable_trials.Fields.Fields[J].AsFloat;
      Inc(J);
   end;
   ...
end;
 
The problem with a database design like this is that if next week, you need 103 values, you need to change your database, AND your program.

separating these values into a child table will solve this.

Not knowing what you are actually trying to model, I have to fall back on giving you a generic example

A Table may look like:

ParentTable
--------------
ParentTableID (primary key)
ParentTableColumn1
ParentTableColumn2

A Child Table where ParentTable is referenced:

ChildTable
---------------
ParentTableID (primary Key, foreign key - references ParentTable)
ChildTableID (primary Key)
ChildTableColumn1

or

ChildTable
---------------
ChildTableID (primary Key)
ParentTableID (foreign key - references ParentTable)
ChildTableColumn1

Difference between the two child tables are that the ParentTableID is or is not part of the primary key of the child table. In your case, I would surmise you would need ParentTableID to be part of the primary ID..

So your Parent Table would hold basic information about what each value (your spinedit values) refers to, and in your case, your 100 spin edit values would be in the child table. Only one column in the child table is needed, not 100..

To get the spinedit values, a query may look like:

Select ChildTableColumn1
From ChildTable, ParentTable
Where ParentTable.ParentTableID = ChildTable.ParentTableID and
ParentTableID = :paramValue

Set the Parameter for the query to the instance you are interested in.
 
Thank..I get it. My schema with the spinedits will always have a value of 101. So the table will not change.I thought i could create an array field and I was not aware of a feature like that. I use the free embedded nexus database. Works great for my small app.
Appreciate your input.
P
 
In database design, if you have the urge to use an array, then use a (sub)table!
This is probably the other half of the design-error I mentioned earlier in this thread :-(
 
@TonHu
Not sure on how i could get rid of my spinedit or textedit. I am scanning 101 patches of gray and displaying these values into spinedits to manually adjust them.

How can i get a better way to display 101 values?
Thanks.
P
 
While i am at it and trying to make my code cleaner and more effective, how can i find out the number of a component. For example, instead of writing square001.value := ...
i would like to write:
TSpinEdit(Components).Value :=

But i need to know the value of i when my focus is in this component.
Thanks.
P
 
You can set the spinedit's TAG property set to the component's number.

So SpinEdit3.Tag := 3;

Probably best done at design time in the object inspector...
 
ok..Not sure if i am doing it right. I setup the tag of my first spinedit to 1 in the object inspector.
In my code i now have:
TSpinEdit(Components[Tag]).Value := x;

That gives me an A/V...
The reason i am doing that is i can point all my spinedit to one event instead of duplicating then.
 
My understanding was that you wanted an easy way to know the sequence number of your spinedits..

i.e.

spinedit1
spinedit2
...
spineditn

I suggested to make
spinedit1.tag = 1;
spinedit2.tag = 2
..
spineditn.tag = n;

That does not change it's position within the component list. Doing that would need to be done at run time, rather than design time. You'd need to go through each component, when it is a spinedit, set it's tag property to the component number.

But truthfully that's a lot of work for very little gain, what you should do instead is set up a component array.

Code:
type
   TForm1 = class(TForm)
     ..
     procedure TForm1.FormCreate(Sender: TObject);
   private
     SpinEdits:  Array[1..100] of TSpinEdit;
   end;

procedure TForm1.FormCreate(Sender: TObject);
var
   I, J: Integer;
begin
   For I := 1 to 100 do
      For J := 0 to Form.ComponentCount - 1 do
         if Form.Components[J] is TSpinEdit then
            SpinEdits[I] := Form.Component[J];
end;

Now you should be able to set the readonly property rather easily.

Code:
var
   I: Integer;
begin
   For I := 1 to 100 do
      SpinEdits[I].ReadOnly := True;
end;

Also, this is untested, I don't have Delphi here to test it.
 
Small modification

Code:
SpinEdits[I] := Form.Component[J] as TSpinEdit;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top