Solved

Custom Classes

Posted on 2002-05-22
8
195 Views
Last Modified: 2013-11-23
I'm trying to display some data on a form.  Each data entry has similar properties (a label, and edit box, a checkbox and some hidden string, boolean and integer info).

I would like to create a dyanmic array of components.  Each array element should have a Label, an Edit Box and a Checkbox, and some variables (such as boolean and integer variables).  I would like to make it so that I can display as many or as few of these "components" as I need on the form.

I'm assuming I have to create my own class, and create an array of them, but how do I go about doing that (syntactically).  I've been having some troubles especially with the creation of the objects.
0
Comment
Question by:PaulKorzycki
  • 4
  • 2
  • 2
8 Comments
 
LVL 12

Expert Comment

by:Lee_Nover
Comment Utility
you can make smth like :

TSomeStuff = class(TComponent)
  private
    FLabel: TLabel;
    FEdit: TEdit;
    FCheckBox: TCheckBox;
    FExtString: string;
    FExtBool: Boolean;
    FExtInteger: Integer;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Edit: TEdit read FEdit;
    property CheckBox: TCheckBox read FcheckBox;
    property ExtString: string read FExtString write FExtString;
    property ExtBool: boolean read FExtBool write FExtBool;
    property ExtInteger: Integer read FExtInteger write FExtInteger;
  end;


implementation

constructor TSomeStuff.Create(AOwner: TComponent);
begin
     inherited;
     FLabel:=TLabel.Create(Self);
     FEdit:=TEdit.Create(Self);
     FCheckBox:=TCheckBox.Create(Self);
     FExtBool:=false;
     FExtInteger:=0;
     FExtString:='';
end;

destructor TSomeStuff.Destroy;
begin
     // do some cleanup
     inherited;
end;




I suggest you use TObjectList instead of an array
better yet would be to make a collection
that component being a TCollectionItem
0
 
LVL 12

Expert Comment

by:Lee_Nover
Comment Utility
you can make smth like :

TSomeStuff = class(TComponent)
  private
    FLabel: TLabel;
    FEdit: TEdit;
    FCheckBox: TCheckBox;
    FExtString: string;
    FExtBool: Boolean;
    FExtInteger: Integer;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Edit: TEdit read FEdit;
    property CheckBox: TCheckBox read FcheckBox;
    property ExtString: string read FExtString write FExtString;
    property ExtBool: boolean read FExtBool write FExtBool;
    property ExtInteger: Integer read FExtInteger write FExtInteger;
  end;


implementation

constructor TSomeStuff.Create(AOwner: TComponent);
begin
     inherited;
     FLabel:=TLabel.Create(Self);
     FEdit:=TEdit.Create(Self);
     FCheckBox:=TCheckBox.Create(Self);
     FExtBool:=false;
     FExtInteger:=0;
     FExtString:='';
end;

destructor TSomeStuff.Destroy;
begin
     // do some cleanup
     inherited;
end;




I suggest you use TObjectList instead of an array
better yet would be to make a collection
that component being a TCollectionItem
0
 
LVL 12

Expert Comment

by:Lee_Nover
Comment Utility
damn .. why did it get posted twice ?

anyway a full example :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Contnrs;

type
  TSomeStuff = class(TComponent)
  private
    FLabel: TLabel;
    FEdit: TEdit;
    FCheckBox: TCheckBox;
    FExtString: string;
    FExtBool: Boolean;
    FExtInteger: Integer;
  public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy; override;
  published
    property xLabel: TLabel read FLabel;
    property Edit: TEdit read FEdit;
    property CheckBox: TCheckBox read FcheckBox;
    property ExtString: string read FExtString write FExtString;
    property ExtBool: boolean read FExtBool write FExtBool;
    property ExtInteger: Integer read FExtInteger write FExtInteger;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    MyList: TObjectList;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TSomeStuff }

constructor TSomeStuff.Create(AOwner: TComponent);
begin
     inherited;
     FLabel:=TLabel.Create(Self);
     FEdit:=TEdit.Create(Self);
     FCheckBox:=TCheckBox.Create(Self);
     FExtBool:=false;
     FExtInteger:=0;
     FExtString:='';
end;

destructor TSomeStuff.Destroy;
begin
     // do some cleanup
     inherited;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
     MyList:=TObjectList.Create(true);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
     FreeAndNil(MyList);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
     if MyList.Count > 0 then
        MyList.Delete(MyList.Count-1);
     Caption:=IntToStr(MyList.Count);
end;

procedure TForm1.Button1Click(Sender: TObject);
var tmpSS: TSomeStuff;
begin
     tmpSS:=TSomeStuff.Create(nil);
     tmpSS.FEdit.Text:='lala';
     tmpSS.xLabel.Caption:='boo';
     MyList.Add(tmpSS);
     Caption:=IntToStr(MyList.Count);
end;

end.




you handle the positions and other things yourself :)
but to avoid all this you can simply use Frames
create a frame, put some compos on it
then create the frames like I did with that TSomeStuff
and add it to the objectlist
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
Hi PaulKorzycki,

let suppose you created your own control. In additional, you can create global TList (instead of dynamic array) and automatically add control there in constructor and remove it in destructor.

interface

var
  GL: TList;
....

implemantation

constructor TSomeControl.Create(AOwner: TComponent);
begin
  Inherited;
  ...
  GL.Add(Self);
end;

destructor TSomeClass.Destroy;
begin
  GL.Remove(Self);
  ...
  inherited;
end;

...
initialization
  GL := TList.Create;
finalization
  GL.Free;
end.


-------
Igor.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:PaulKorzycki
Comment Utility
Thanks for all of your help guys.  I think I'm getting closer, I just have a few questions:

1) Lee_Nover: you talked about TObjectList, but I can't find reference to it in Delphi 4 (the help lists nothing).  Is this the same as TList?  So what is the difference between TList and TCollectionItem?  Why use one instead of the other?

2) ITugay: I understand your example, but it looks like you are adding the objects into the array within the actual constructor of the object?  Ideally I would like to have the objects defined in thier own units, and then be able to create them from their own program.  Currently I do the following:

------------------------------

(unit TSomeControl defined in seperate file...)
...
var GL: array of TSomeControl;

...
(in the main body, when I want to add my new control into the form...)

  setlength(GL, Length(GL)+1);
  GL[Length(GL)-1]:=TSomeControl.Create(self);
  with (GL[Length(GL)-1]) do
  begin
    Parent:=self;
    Top:=50
    Left:=50;
  end;

....
(on program exit...)

for i:=0 to (length(GL)-1) do GL[i].Free;

------------------------------

This does work in fact, but I suppose TList would be a better soloution.  How do I create the object and stuff it into the TList *not* in the unit (ie: do it in the main form)?  Where should I initialize and destroy the list?

3) Lee_Nover: TSomeStuff.Create creates every control, should TSomeStuff.Destroy "Free" all of them, or will the sub components get freed automatically?  Likewise, in my example when I free the array, does everything get taken with it, or do I have to do each component first?

4) (This is an aside) How can I publish certain properties and not others?  For example, if in CheckBox, I don't want the "Checked" property to get published down?

I think that's it for now...thanks again for all your help, I know most of these are newbie questions, but I think its about time I finally solidify these concepts.

Thanks!
0
 
LVL 12

Accepted Solution

by:
Lee_Nover earned 100 total points
Comment Utility
I have D6 so I don't know what classes are there in D4
TObjectList is in the contnrs unit (don't know about D4)
if you want to hide a property from the OI then move it to the public section

you can create your own list of your own type
here's an example:

type
  TSections = class;

  TSection = class(TObject)
  private
  public
    Area: TRect;
    SecCol: Integer;
    SecRow: Integer;
    SecIndex: Integer;
    Sensitivity: Byte;
    LastChange: Byte;
    Selected: Boolean;
    FSections: TSections;
    constructor Create(ASections: TSections);
    procedure Clear;
  end;

  TSections = class(TList)
  private
    FRows: Integer;
    FColumns: Integer;
    FHeight: Integer;
    FWidth: Integer;
    FSectionHeight: Integer;
    FSectionWidth: Integer;
    FDefSensitivity: Byte;
  protected
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
    function GetItem(Index: Integer): TSection;
    procedure SetItem(Index: Integer; Item: TSection);

    function GetSection(Column, Row: Integer): TSection;
    procedure SetSection(Column, Row: Integer; Item: TSection);

  public
    constructor Create(AColumns, ARows: Integer);
    destructor Destroy;override;

    function Add(Section: TSection): Integer;overload;
    function Add: TSection;overload;
    function Insert(Index: Integer; Section: TSection): Integer;overload;
    function Insert(Index: Integer): TSection;overload;
    procedure Delete(Index: Integer);
    procedure Clear;override;

    procedure SetColumns(Value: Integer);
    procedure SetRows(Value: Integer);
    procedure SetHeight(Value: Integer);
    procedure SetWidth(Value: Integer);

    function LoadFromFile(const FileName: string): Boolean;
    function SaveToFile(const FileName: string): Boolean;
    procedure Update;
    procedure UpdateSectionRects;

    function SectionToIndex(const Col, Row: Integer): Integer;
    function IndexToSection(const Index: Integer; var Col, Row: Integer): Integer;

    // properties
    property Rows: Integer read FRows write SetRows;
    property Columns: Integer read FColumns write SetColumns;
    property Height: Integer read FHeight write SetHeight;
    property Width: Integer read FWidth write SetWidth;
    property DefaultSensitivity: Byte read FDefSensitivity write FDefSensitivity default 50;
    property Items[Index: Integer]: TSection read GetItem write SetItem;
    property Section[Column, Row: Integer]: TSection read GetSection write SetSection;

  end;



implementation

{ ---- TSections ----}

constructor TSections.Create(AColumns, ARows: Integer);
begin
     inherited Create();
     if AColumns < 1 then AColumns:=1;
     if ARows < 1 then ARows:=1;
     Add;
     FColumns:=1;
     FRows:=1;
     Rows:=ARows;
     Columns:=AColumns;
end;

destructor TSections.Destroy;
begin
     inherited;
end;

function TSections.Add(Section: TSection): Integer;
begin
     Result:=inherited Add(Section);
end;

function TSections.Add: TSection;
begin
     Result:=TSection.Create(Self);
     Result.SecIndex:=Count;
     Result.Sensitivity:=FDefSensitivity;
     inherited Add(Result);
end;

function TSections.Insert(Index: Integer): TSection;
begin
     Result:=TSection.Create(Self);
     Result.Sensitivity:=FDefSensitivity;
     inherited Insert(Index, Result);
end;

function TSections.Insert(Index: Integer; Section: TSection): Integer;
begin
     Section.SecIndex:=Index;
     inherited Insert(Index, Section);
     Result:=Index;
end;

procedure TSections.Delete(Index: Integer);
begin
     inherited Delete(Index);
end;

procedure TSections.Clear;
var I: Integer;
begin
     if Count < 2 then exit;
     for I:=Count-1 downto 0 do
         Delete(I);

     Add;
     FColumns:=1;
     FRows:=1;
     inherited;
end;

procedure TSections.Notify(Ptr: Pointer; Action: TListNotification);
begin
     if Action = lnDeleted then begin
        FreeAndNil(Ptr);
     end;
     inherited Notify(Ptr, Action);
end;

function TSections.GetItem(Index: Integer): TSection;
begin
     Result:=TSection(inherited Items[Index]);
end;

procedure TSections.SetItem(Index: Integer; Item: TSection);
begin
     inherited Items[Index]:=Item;
end;

function TSections.SectionToIndex(const Col, Row: Integer): Integer;
begin
     Result:=(Row * FColumns) + Col;
end;

function TSections.IndexToSection(const Index: Integer; var Col, Row: Integer): Integer;
begin
     if (Index < FColumns) then begin // because of division by zero
        Row:=0;
        Col:=Index;
     end else begin
        Row:=(Index div FColumns);
        Col:=(Index mod FColumns);
     end;
     Result:=0;
end;

function TSections.GetSection(Column, Row: Integer): TSection;
var I: Integer;
begin
     I:=SectionToIndex(Column, Row);
     if I >= Count then I:=Count-1;
     Result:=TSection(inherited Items[I]);
end;

procedure TSections.SetSection(Column, Row: Integer; Item: TSection);
var I: Integer;
begin
     I:=SectionToIndex(Column, Row);
     if I >= Count then I:=Count-1;
     inherited Items[I]:=Item;
end;

procedure TSections.SetRows(Value: Integer);
var r, c, I: Integer;
begin
     if Value = FRows then exit;
     if Value > FRows then begin
        for r:=FRows to Value-1 do
            for c:=0 to FColumns-1 do
                with Add do begin
                  SecRow:=r;
                  SecCol:=c;
                end;
     end else begin
        for r:=FRows-1 downto Value do
            for c:=FColumns-1 downto 0 do begin
                I:=SectionToIndex(c, r);
                Delete(I);
            end;
     end;
     FRows:=Value;
     FSectionHeight:=FHeight div FRows;
     Update;
end;

procedure TSections.SetColumns(Value: Integer);
var r, c, cc, I: Integer;
begin
     if Value = FColumns then exit;
     cc:=FColumns;
     if Value > FColumns then begin
        FColumns:=Value;
        for r:=0 to FRows-1 do
            for c:=cc to Value-1 do begin
                I:=SectionToIndex(c, r);
                with Insert(I) do begin
                  SecCol:=c;
                  SecRow:=r;
                end;
            end;
     end else begin
        for r:=FRows-1 downto 0 do
            for c:=FColumns-1 downto Value do begin
                I:=SectionToIndex(c, r);
                Delete(I);
            end;
     end;
     FColumns:=Value;
     FSectionWidth:=FWidth div FColumns;
     Update;
end;

procedure TSections.SetHeight(Value: Integer);
begin
     if Value = FHeight then exit;
     FHeight:=Value;
     FSectionHeight:=FHeight div FRows;
     Update;
end;

procedure TSections.SetWidth(Value: Integer);
begin
     if Value = FWidth then exit;
     FWidth:=Value;
     FSectionWidth:=FWidth div FColumns;
     Update;
end;

procedure TSections.Update;
begin
     UpdateSectionRects;
end;

procedure TSections.UpdateSectionRects;
var c, r: Integer;
begin
     if (Rows < 1)or(Columns < 1) then exit;
     for r:=0 to FRows-1 do
         for c:=0 to FColumns-1 do
             try
                with Section[c, r].Area do begin
                  Top:=(FRows - r -1) * FSectionHeight; // r * FSectionHeight; // it really should be like this !!! dunno why it show weird values
                  Bottom:=Top + FSectionHeight -1;
                  Left:=c * FSectionWidth;
                  Right:=Left + FSectionWidth -1;
                end;
             finally
             end;
end;

function TSections.LoadFromFile(const FileName: string): Boolean;
var Ini: TIniFile;
    I: Integer;
    DefSens: Byte;
begin
     Result:=true;
     Ini:=TIniFile.Create(FileName);
     with Ini do
       try
          if Count > 0 then Clear;
          Columns:=ReadInteger('Sections', 'Columns', 1);
          Rows:=ReadInteger('Sections', 'Rows', 1);
          DefSens:=ReadInteger('Detection', 'DefSensitivity', 50);

          // setting the columns and rows already creates the items
          for I:=0 to Count-1 do
              with Items[I] do begin
                Sensitivity:=ReadInteger('Sections', Format('Sec%d:', [I]), DefSens);
                LastChange:=0;
              end;

       finally
          Free;
       end;
end;

function TSections.SaveToFile(const FileName: string): Boolean;
var Ini: TIniFile;
    I: Integer;
begin
     Result:=true;
     Ini:=TIniFile.Create(FileName);
     with Ini do
       try
          if Count < 1 then begin
             EraseSection('Sections');
             WriteInteger('Sections', 'Columns', Columns);
             WriteInteger('Sections', 'Rows', Rows);
             WriteInteger('Sections', 'DefSensitivity', 50);
          end else begin
             WriteInteger('Sections', 'Columns', Columns);
             WriteInteger('Sections', 'Rows', Rows);
             WriteInteger('Sections', 'DefSensitivity', 50);

             for I:=0 to Count-1 do
                 with Items[I] do
                   try
                      WriteInteger('Sections', Format('Sec%d:', [I]), Sensitivity);
                   except
                   end;
          end;
       finally
          Free;
       end;
end;



check out Add, Insert, GetItem, SetItem
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
No, problem. Yoy can remove GL.Add and GL.Remove from constructor and destructor.

declare FList: Tlist property in your control. In destructor, check that this property assigned and then remove reference. Bellow you can see a sample:

  TSomeControl = ...
  private
    FList: TList;
    procedure SetList(AList: TList);
  public
   
    property List: TList read FList write SetList;
    destructor destroy; override;
...

procedure TSomeControl.SetList(Alist: TList);
begin
  FList := AList;
  if FList <> nil then
    FList.Add(Self);
end;

destructor TSomeControl.Destroy;
begin
  if FList <> nil then
    FList.Remove(Self);
  inherited;
end;


.....
// how to create control and place it into TList
var
  GL: TList; // place it and initialize it in any unit you like.

var
  C: TSomeControl;
begin
  C := TSomeControl.Create(Self);
  C.List := GL; // here is list assignment
  C.Width := 100;
  C.Parent := Self;
end;

------
Igor.
0
 

Author Comment

by:PaulKorzycki
Comment Utility
Thanks for all of the help!  Sorry it took so long for me to accept the answer!

Paul
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now