runtime components handling

I use the TJVScrollMax a Jedi component. I generate a number of bands inside it at runtime. Inside every Band I must create a number of standard components such as EditBoxes and ComboBoxes, CheckBoxes, labels and buttons. I've done this part with the creation of the components but I am sure I am missing something, since I will describe you next, what I need to happen.
So the user enters the number of bands to be created and then presses a button that begins creating the components and showing them.
Every Band has among other components, a button on it with "Validate" caption. This button will close the currently expanded band and expand the next band in order to allow the user to fill the edits, and comboboxes in the next band.

After the user fills the edits and other components with data on all bands... there is one button on the form which will begin to gather data from all the bands and insert them in a database.
I DO NOT need help with SQL, I only need help with how to handle the runtime created components, let's say... I need that on the final Button onClick event, a Memo should be filled with the data entered in the bands.
I will explain in the code better:
First I will paste the dfm and then the pas file:


object Form1: TForm1
  Left = 343
  Top = 111
  Width = 698
  Height = 651
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 4
    Width = 54
    Height = 13
    Caption = 'Nr. Obiecte'
  end
  object Image1: TImage
    Left = 228
    Top = 24
    Width = 15
    Height = 15
    AutoSize = True
    Picture.Data = {
      0B544A76474946496D6167659C0300004749463839610F000F00F700000B4271
      0C4472F7FAFB1B5A8F050E16081520040B10050C131147753C698ED5DFE64E76
      9836658B050E1804070A0D45739FB6C7C6D4DE164B7899B1C5F8F9F9E1E8EE59
      7F9F7A99B30816220305077292AD104674F6F7F7F1F6F805121CA7BCCDE7EDF2
      BECDD9F2F3F3EAEFF2C2D1DC0C4372124876184D790E4574030506275982CCD8
      E2FCFDFDFBFCFC0405070A4271040A0E1A588B0404041C5D94FDFEFE00000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000000000000000000000000000000000000000002C0000
      00000F000F000008810067081C48B0E00C1908132A445860C0411A1023469440
      23438C871227526C705146C689016838E8F8918684132F68B820995142821710
      5492A438F18505882B6710304953C20B15105BE4F4F8428251091B04041D4AC3
      4400A3002A44144A12C48B07123E48A47A50C447166029A4B8880186590F06CC
      AA8571C0A1C1B7330202003B}
  end
  object jvs: TJvScrollMax
    Left = 8
    Top = 40
    Width = 673
    Height = 441
    ButtonFont.Charset = DEFAULT_CHARSET
    ButtonFont.Color = clWindowText
    ButtonFont.Height = -9
    ButtonFont.Name = 'Small Fonts'
    ButtonFont.Style = []
    AutoHeight = False
    OneExpanded = True
    ParentColor = True
    TabOrder = 0
  end
  object Button1: TButton
    Left = 100
    Top = 12
    Width = 119
    Height = 25
    Caption = 'Genereaza obiecte'
    TabOrder = 1
    OnClick = Button1Click
  end
  object Edit1: TEdit
    Left = 8
    Top = 16
    Width = 89
    Height = 21
    TabOrder = 2
    Text = '4'
  end
  object Button2: TButton
    Left = 580
    Top = 488
    Width = 101
    Height = 25
    Caption = 'Analyze'
    TabOrder = 3
  end
  object Memo1: TMemo
    Left = 8
    Top = 516
    Width = 673
    Height = 101
    Lines.Strings = (
      'Memo1')
    TabOrder = 4
  end
end
LVL 3
GhitzaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

GhitzaAuthor Commented:
And now the code:

unit MainU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, JvScrollMax, ExtCtrls, JvComponent, JvGIF;

type
  TForm1 = class(TForm)
    jvs: TJvScrollMax;
    Button1: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    Image1: TImage;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure onValidxClick(Sender:TObject);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  paneluri : Array [1..8] of TComponent;
  butoane  : Array [1..8] of TComponent;
  Sumeasig : Array [1..8] of TComponent;
  primesub : Array [1..8] of TComponent;
  primeinc : Array [1..8] of TComponent;
  checkuri : Array [1..8] of TComponent;
  combouri : Array [1..8] of TComponent;
  imagini : Array [1..8] of TComponent;

implementation

{$R *.dfm}


procedure TForm1.OnValidxClick(Sender:TObject);
var
  tgu:integer;
  nr,i:Integer;
  img:TImage;
  bndu:TJvScrollMaxBand;
  nm,numenou:string;
begin
  nr:=((Sender as TButton).Parent as TJvScrollMaxBand).Order;
  ((Sender as TButton).Parent as TJvScrollMaxBand).Expanded:=false;
  nm:=((Sender as TButton).Parent as TJvScrollMaxBand).Name;
  numenou:='';
  for i:=1 to StrLen(PChar(nm)) do
  begin
    If i>=5 then numenou:=numenou+nm[i];
    end;
  numenou:='jvsb'+IntToStr(StrToInt(numenou)+1);
//  ShowMessage(numenou);
  bndu:=TJvScrollMaxBand(FindComponent(numenou));
//  bndu.Expanded:=true;
  TImage(FindComponent('img1')).Visible:=True;
  end;


procedure TForm1.Button1Click(Sender: TObject);
var
   bnd:TJvScrollMaxBand;
   b:TButton;
   cmb:TComboBox;
   ckb:TCheckBox;
   pnl:TPanel;
   lbl:TLabel;
   ed1,ed2,ed3,ed4:TEdit;
   img:TImage;
   i:integer;
   x:string;
begin
For i:=1 to StrToInt(Edit1.Text) do
begin
  bnd:=TJvScrollMaxBand.Create(jvs);
  bnd.Name:='jvsb'+IntToStr(i);
  bnd.Caption:='jvsb'+IntToStr(i);
  bnd.Height:=150;
  jvs.AddBand(bnd);

// panel header
  pnl:=TPanel.Create(Form1);
  pnl.Parent:=bnd;
  pnl.Height:=18;
  pnl.Name:='pnl'+IntToStr(i);
  pnl.Font.Color:=clWhite;
  pnl.Caption:='Riscul nr.:'+IntToStr(i);
  pnl.Color:=clBlue;
  pnl.Align:=alTop;

// poza validare
  img:=TImage.Create(Form1);
  img.Parent:=pnl;
  img.Name:='img'+intToStr(i);
  img.Left:=1;
  img.Top:=1;
  img.Picture:=Image1.Picture;
  img.Visible:=False;
  img.Transparent:=True;

  // generez LABEL (titlu combobox)
  lbl:=TLabel.Create(Form1);
  lbl.Parent:=bnd;
  lbl.Left:=10;
  lbl.Top:=22;
  lbl.Caption:='Alegeti obiectul/riscul asigurat';

  // generez combobox de obiecte/riscuri
  cmb:=TComboBox.Create(Form1);
  cmb.Name:='cmb'+IntToStr(i);
  cmb.Parent:=jvs.Bands[i-1];
  cmb.Items.Add('Autovehicul');
  cmb.Items.Add('Persoane');
  cmb.Items.Add('Echipamente suplimentare');
  cmb.Items.Add('Alte riscuri');
  cmb.Top:=35;
  cmb.Left:=10;
  cmb.Width:=250;
  cmb.ItemIndex:=0;

  ckb:=TCheckBox.Create(Form1);
  ckb.Parent:=bnd;
  ckb.Top:=35;
  ckb.Left:=275;
  ckb.Caption:='Cu rate';

  // generez LABEL (titlu Suma asigurata)
  lbl:=TLabel.Create(Form1);
  lbl.Parent:=bnd;
  lbl.Left:=10;
  lbl.Top:=60;
  lbl.Caption:='Suma asigurata';

  // Generez EDIT pt suma asigurata
  ed1:=TEdit.Create(Form1);
  ed1.Parent:=bnd;
  ed1.Name:='sa'+IntToStr(i);
  ed1.Ctl3D:=false;
  ed1.Left:=10;
  ed1.Top:=72;
  ed1.Width:=80;
  ed1.Text:='0';
  ed1.OnChange:=nil;

  // generez LABEL (titlu PRIMA subscrisa)
  lbl:=TLabel.Create(Form1);
  lbl.Parent:=bnd;
  lbl.Left:=100;
  lbl.Top:=60;
  lbl.Caption:='Prima subscrisa';

  // Generez EDIT pt PRIMA subscrisa
  ed2:=TEdit.Create(Form1);
  ed2.Name:='ps'+IntToStr(i);
  ed2.Parent:=bnd;
  ed2.Ctl3D:=false;
  ed2.Left:=100;
  ed2.Top:=72;
  ed2.Width:=80;
  ed2.Text:='0';

  // generez LABEL (titlu PRIMA incasata)
  lbl:=TLabel.Create(Form1);
  lbl.Parent:=bnd;
  lbl.Left:=190;
  lbl.Top:=60;
  lbl.Caption:='Prima incasata';

  // Generez EDIT pt PRIMA incasata
  ed3:=TEdit.Create(Form1);
  ed3.Name:='pi'+IntToStr(i);
  ed3.Parent:=bnd;
  ed3.Ctl3D:=false;
  ed3.Left:=190;
  ed3.Top:=72;
  ed3.Width:=80;
  ed3.Text:='0';

  // generez buton de validare risc
  b:=TButton.Create(Form1);
  b.Name:='btn'+IntToStr(i);
  b.Caption:='Valideaza';
  b.Parent:=jvs.Bands[i-1];
  b.Top:=jvs.Bands[i-1].Height-30;
  b.Left:=jvs.Bands[i-1].Width-75;
  b.Width:=70;
  b.Height:=25;
  b.OnClick:=onValidxClick;



  bnd.ButtonVisible:=false;
  ed1.FreeOnRelease;
  ed2.FreeOnRelease;
  ed3.FreeOnRelease;
  bnd.FreeOnRelease;
end;

jvs.Bands[0].Expanded:=True;
bnd.FreeOnRelease;
ed1.FreeOnRelease;
ed2.FreeOnRelease;
ed3.FreeOnRelease;


for i := 1 to 8 do
    begin
    paneluri[i] := FindComponent('pnl' + IntToStr(i));
    butoane[i] := FindComponent('btn' + IntToStr(i));
    Sumeasig[i] := FindComponent('sa' + IntToStr(i));
    primesub[i] := FindComponent('ps' + IntToStr(i));
    primeinc[i] := FindComponent('pi' + IntToStr(i));
    checkuri[i] := FindComponent('ckb' + IntToStr(i));
    combouri[i] := FindComponent('cmb' + IntToStr(i));
    imagini[i] := FindComponent('img' + IntToStr(i));
    end;
end;

end.
GhitzaAuthor Commented:
//****************
 This is my FIRST problem...
In the OnValidxClick event  --  I must expand the next band which should be very easy since the function  looks like this:

band2.Expand:=true;
(but in order to do this I must be able to refer to the next band... and I don't seem to be able to,
I tried to do it like this:

  bndu:=TJvScrollMaxBand(FindComponent(numenou));  // where numenou is a string that is built with the name of the next band component
  bndu.Expanded:=true;
But I get some violation error. So I need the event rewritten in order to do what I need it to do

// ****************
And the SECOND problem is that I do not seem to create the components correctly, since when I enter a value in one EditBox... all the following bands seem to get altered with the same text I enter in the first band. And I repeat: all the bands contain same type of components as you will see after you build my project (but they are distinct)


// So I must be able to address any component from any band in some way in order to gather the data entered there, such as Edit text, ComboBox text, CheckBox state and so on

I am sure I missed something somewhere...
Anyone any ideea?
TNameCommented:
//Problem1: See if this helps (hope I understand your intention correctly)


procedure TForm1.OnValidxClick(Sender:TObject);
var
  tgu:integer;
  nr,i:Integer;
  img:TImage;
  bndu:TJvScrollMaxBand;
  nm,numenou:string;
begin
  nr:=((Sender as TButton).Parent as TJvScrollMaxBand).Order;
  ((Sender as TButton).Parent as TJvScrollMaxBand).Expanded:=false;
  nm:=((Sender as TButton).Parent as TJvScrollMaxBand).Name;
  numenou:='';
  for i:=1 to StrLen(PChar(nm)) do
  begin
    If i>=5 then numenou:=numenou+nm[i];
    end;
  numenou:='jvsb'+IntToStr(StrToInt(numenou)+1);

  bndu:=nil;
  for i:=0 to jvs.BandCount-1 do begin
    if TButton(Sender).Parent=jvs.Bands[i] then
      if i< jvs.BandCount-1 then
        bndu:=jvs.Bands[i+1];
  end;

  if  bndu<>nil then
    bndu.Expanded:=true;
  TImage(FindComponent('img1')).Visible:=True;
end;
OWASP Proactive Controls

Learn the most important control and control categories that every architect and developer should include in their projects.

TNameCommented:
//BTW, I think you can cut down the procedure like this:

procedure TForm1.OnValidxClick(Sender:TObject);
var
  i:Integer;
  bndu:TJvScrollMaxBand;
begin
  TJvScrollMaxBand(TButton(Sender).Parent).Expanded:=false;
  bndu:=nil;
  for i:=0 to jvs.BandCount-1 do begin
    if TButton(Sender).Parent=jvs.Bands[i] then
      if i<jvs.BandCount-1 then
        bndu:=jvs.Bands[i+1];
  end;
  if  bndu<>nil then
    bndu.Expanded:=true;
  TImage(FindComponent('img1')).Visible:=True;
end;
TNameCommented:
>And the SECOND problem is...
I think your second problem has gone away now... Can you confirm this?

But there are a few other problems, e.g. Should the user be able to hit the "Genereaza obiecte" button more then once? If yes, then you have to change the creation process, as you would try to create the same bands again, and you'll get an error message.
TNameCommented:
//And this version will also update the Validate-image:

procedure TForm1.OnValidxClick(Sender:TObject);
var
  i,j:Integer;
  bndu:TJvScrollMaxBand;
begin
  TJvScrollMaxBand(TButton(Sender).Parent).Expanded:=false;
  bndu:=nil;
  for i:=0 to jvs.BandCount-1 do begin
    if TButton(Sender).Parent=jvs.Bands[i] then begin
      TImage(FindComponent('img'+IntToStr(i+1))).Visible:=True;
      if i<jvs.BandCount-1 then
        bndu:=jvs.Bands[i+1];
    end;
  end;
  if  bndu<>nil then
    bndu.Expanded:=true;
end;
GhitzaAuthor Commented:
Thanks so far... the first problem is solved... the stuff you removed from the event was placed there because I tryed more ways to access the components. So it was garbage :)
but the big main problem is the second... where I seem to have a problem with the unicity of the components.
Just try the next steps:
generate bands... and after that on the first generated band enter some values in the first edit box (for example).
After this just press "validate" button to move to the next band... and you will notice that the edit box (the brother of the one you entered text in above) has the same value as the one in the previous band... and all the way down, until the last band.
Somehow, when I enter a value in the first edit... it perpetuates to all the edits created

So I need to make them be unique... every band must have it's own values inside the editboxes and check boxes (by the way, the same stuff happens to any component I create in the bands)
And after this problem is solved I sayd I needed help in accessing values in the compojnents of the bands... So in the Analyze button I would need you to gather texts from the edits from every edit from band1 and band2 for example (so I could understand how to access them all.
As I explained above I need to build some sql (INSERTs) using the data entered in each band,
so for the first band there will be an insert with data from the components of the same band, for the second band INSERT with data from the second band... and so on...
Also please suggest how should I create them to avoid getting error when user generates more than once the bands...

Thanks so far
GhitzaAuthor Commented:
Wow... I am shoked... but you were right... my second problem is gone (the first part... with the unicity)
And I know why it did too... The problem was that I was seeing the same band moved bellow with one band every time I clicked on validate.
So the unicity is solved
I'll check to see if  can access the components without help from you, but anyway I would appreciate if you would assist me.
Thanks again
TNameCommented:
Glad to have helped and glad to help ;)

I'll have a look at the creation process, but it would be good to know: If the user clicks the Generate button again, do you want the old bands replaced by new ones, or do you want new bands added to the old ones?
GhitzaAuthor Commented:
I would need the old bands to dissappear and new ones should appear, with new components inside... I mean... empty ones (not with the old values entered previously...).
Imagine you want to allow the user to enter all the cars of all garages in the city with all the details of the cars in a database.
First the user will declare how many cars there are... in the first garage then in each created band, he will enter the information about the cars.
When he finishes he will want to process another garage... with a whole new set of cars and details of the cars...

So this is a way of imagining it.
Thanks again for your time

TNameCommented:
//Here's one way to collect the text values from the different edits:
//First, declare

procedure Analyse;

//in the private section of your Form1 class declaration.
//Then try this. The sub-routine CollectSums  of the Analize procedure does all the work


procedure TForm1.Button2Click(Sender: TObject);
begin
  Analyse;
end;

procedure TForm1.Analyse;
 function CollectSums(Indx:Integer; EditType:Byte):String;
 var
  s:String;
 begin
   s:='';
   result:='';
   if jvs.BandCount>0 then begin
      case EditType of
         1: s:=TEdit(FindComponent('sa'+IntToStr(Indx))).Text;
         2: s:=TEdit(FindComponent('ps'+IntToStr(Indx))).Text;
         3: s:=TEdit(FindComponent('pi'+IntToStr(Indx))).Text;
      end;
      result:=s;
   end;
 end;
begin
    ShowMessage(CollectSums(1,2));    //First nr. is the band-nr, second nr. is the Edit number
    ShowMessage(CollectSums(1,3));    //So, (1,3) would be the pi edit on band 1
    ShowMessage(CollectSums(3,2));    // and (3,2) would be the ps edit on band 3
    //If there are no bands created, or if the edit is empty, you'll get an empty message box
end;
TNameCommented:
//Or better change
if jvs.BandCount>0 then begin

//to
if jvs.BandCount>=Indx then begin
TNameCommented:
//Simplified version:

procedure TForm1.Button2Click(Sender: TObject);
begin
  Analyse;
end;

procedure TForm1.Analyse;
 function CollectSums(Indx:Integer; EditType:Byte):String;
 begin
   result:='';
   if jvs.BandCount>=Indx then
      case EditType of
         1: result:=TEdit(FindComponent('sa'+IntToStr(Indx))).Text;
         2: result:=TEdit(FindComponent('ps'+IntToStr(Indx))).Text;
         3: result:=TEdit(FindComponent('pi'+IntToStr(Indx))).Text;
      end;
 end;
begin
    ShowMessage(CollectSums(1,3));
    ShowMessage(CollectSums(2,2));
    ShowMessage(CollectSums(3,1));
end;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
TNameCommented:
>I would need the old bands to dissappear and new ones should appear, with new components inside... I mean... empty ones (not with the old values entered previously...).

Simply place this at the very beginning of your Button1Click (Generate) procedure - before the for loop that creates the objects:


if jvs.BandCount >0 then
     for i:=1 to jvs.BandCount do begin
        jvs.Bands[0].Free;  //<--------------  0, not i ! Keep taking out the bottom row... it's like playing Tetris ;)
     end;
TNameCommented:
One more suggestion. Your edits accept any input at the moment.
You could assign an event handler like this to all currency edits, to make them accept only numbers, backspace and just one decimal separator:

procedure TForm1.CustomKeyPress(Sender: TObject; var Key: Char);
var Allowed : set of char;
begin
  if pos (DecimalSeparator,TEdit(Sender).Text) = 0 then
     Allowed := ['0'..'9',#8] + [DecimalSeparator]
  else
     Allowed := ['0'..'9',#8];
  if not (Key in Allowed) then
    Key := #0;
end;

{...}

ed1.OnKeyPress:=CustomKeyPress;

GhitzaAuthor Commented:
Thanks a lot
You are great. It's all I needed. Also the customKeyPressed was one of my next moves, so it's very welcome.
You deserve all the points. I wish I had more points available, but anyway I'll give you a grade A for your help.
Thanks
TNameCommented:
>Thanks
Cu placere :)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.