?
Solved

Im missing the connection between the objects, can someone point me in the right direction.

Posted on 2004-04-01
20
Medium Priority
?
313 Views
Last Modified: 2010-04-05
Should be a fairly easy solutioin but I must be missing something obvious.

Ive got a new class created
TCBRecord = class
  private
    Variable1, Variable2, etc
    <Procedures to set variables, functions to read>
  public
    <Constructor>
    <read/write properties>
  end

TMyForm = class(TForm)
  MyBook : TList

I create a TCBRecord and then add it to MyBook

The thing is that MyBook is not linked to TCBRecord, but to the form it is on.

Im trying to now read the entries from MyBook but I cant access the records.
Obvisouly Im putting the variables in the wrong places but I cant see how to re-arrange things.

The TList must be linked to the form as I want to try and read variables from the records in MyList to display in a stringgrid

Why cant I do
  For iCnt := 0 to (MyBook.Count - 1) do
  begin
    Stringgrid.Cells[Col, Row] := MyBook[iCnt].variable1
  end

So MyBook[iCnt].variable1 is incorrect, how can I now access the data
0
Comment
Question by:mikelittlewood
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 5
  • 4
20 Comments
 
LVL 26

Assisted Solution

by:Russell Libby
Russell Libby earned 400 total points
ID: 10735788

Because TList returns pointers, which your object is, but just needs to be cast back to the proper type.

eg:

Stringgrid.Cells[Col, Row] := TCBRecord(MyBook[iCnt]).variable1



Regards,
Russell
0
 
LVL 11

Accepted Solution

by:
shaneholmes earned 400 total points
ID: 10736389
You could also use a TObjectList    vs   a TList

(found in the Contnrs unit)


 Create it the same as you would a TList

 MyList:= TObjectList.Create;

 but then

 Set its OwnsObjects = True

 MyList:= TObjectList.Create;
 MyList.OwnsObjects:= True;


 Now when the TObjectList is destroyed  

 MyList.free

It will destroy all the objects in the list

in this case, all your  TCBRecords

else

 you will have to iterate through the entire TList and release each object your self.


I also like to wrap my TObjectLists up into my own little list, which uses my Object
so I dont have to typecast

Example:


TMyList = class(TObjectList)
  private
  function GetItem (Index : Integer):TRCBRecord
  procedure SetItem(Index: Integer; const ARecord: TRCBRecord);
  protected
  public
   constructor Create(AOwnsObjects: Boolean = True); reintroduce;
   destructor Destroy; override;
   function Add(Item: TRCBRecord): Integer;
   procedure Delete(Index: Integer);
   property Item [Index : Integer] : TRCBRecord read GetItem write SetItem; default;
  end;


function TMyList.GetItem(Index : Integer):TRCBRecord;
begin
 result := TRCBRecord(Inherited Items [Index]);
end;

procedure TMyList.SetItem(Index: Integer; const ARecord: TRCBRecord);
begin
 inherited Items[Index] := ARecord;
end;

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

function TMyList.Add(Item: TRCBRecord):Integer;
begin
 Result:= inherited Add(Item);
end;


constructor TMyList.Create(AOwnsObjects: Boolean = True);
begin
 inherited Create(AOwnsObjects);
end;

destructor TMyList.Destroy;
begin
 inherited Destroy;
end;


 Hope this helps!

Shane
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10736409
Sorry, Replace MyList with MyBook   <SMILE>

Shane
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 15

Author Comment

by:mikelittlewood
ID: 10736797
Thx to u both for your answers.

Is a TList better to use for say simple lists like strings and integers.
While TObjectList is better for holding objects.

Im gonna award the points to Russell as he did answer my question and solve the issue I had.
But thanks for that complete answer Shane, I think I might re-write the section and create another new class.
Im sorta trying new things out so I appreciate the complete answer.
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10736804
In fact I split the points for you both

thanks again
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10736820

Tlist is good for record pointers, integers, pointers in general; basically anything that is not a TObject decendant. The object list provides a better means for handling objects. Even better (in this case) would have been to create a TCollection and TCollectionItem class setup.

It just depends how much extra work you wish to put into it, and if you do/don't mind handling the memory management yourself.

Thanks for the pts,
Russell


0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10741498
>>Even better (in this case) would have been to create a TCollection and TCollectionItem class setup. <<

Don't mean to be a pain asking too many basic questions, but could you give me some logic as to why this would be better.
It doesnt help that I havent used TCollection before, maybe once I get the full program running how I want it I might do some more experimenting
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10741569
Yeah, i'd like to hear how this would be better also

 listening....

Shane
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10742561
Hey Shane, got another quick question for ya .. following on from the large section you wrote.

I seem to be having some problems getting the correct record out of my TObjectList.
Ive created that wrapper you suggested around my TCBRecord
Not sure if this is correct but ...

Im reading the records from a database into my TCBRecord in a loop and adding to my ObjectList (TMyList)

Temp_CBRecord := TCBRecord.create;
while <Something> do
begin
  Temp_CBRecord.VALUE1  := IBQuery.FieldByName('VALUE1').AsString;
  Temp_CBRecord.VALUE2   := IBQuery.FieldByName('VALUE2').AsString;
  <etc>
  MyList.Add(Temp_CBRecord);
  IBQuery.next
end;

but when I try to access the records outside of this procedure, I only ever seem to read the last entry into the list
at a guess Im saying I shouldnt be adding temporary records to MyList

for RecordIndex:= 0 to (MyList.Count - 1) do
  ReadTCBRecordAndDoSomething(RecordIndex);

0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10742614
We need tos ee this part

ReadTCBRecordAndDoSomething(RecordIndex);


Shane
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10742664

I think we can all agree on the following:

TList   - list for maintiaing generic pointers
TObject - list that is specialized for holding generic objects, but still requires casting to the correct object type in order to use it.

The TCollection is similar to the object list, but offers the
following enhancements.

1.) Takes minimal coding to hande the adding/deleting/casting, as most of this functionality is already encapsulated in the TCollection / TCollectionItemClass.

2.) Can be persisted (because it inherits from TPersistent), which is useful for making this a property of a component, as it also offers a designer.

3.) If you free an object in an object list, you must code the removal from the object list. eg

obj:=TObjectList[1];
obj.Free; // TObjectList now holds a stale pointer at index 1
// The list must now be corrected to remove the item at index 1, because it was
// freed

The collection item on the other hand, will notify the collection of the removal so the developer can feel "free" (so to speak) to call Free on any object in the list, and not have to worry about the list management. Believe it or not, this scenario tends to catch quite a few developers...

So, using your example class, this is all that is required to turn this into a collection/collection item class set.

type
  TCBRecord      = class(TCollectionItem)
  private
     FVariable1: Integer;
     FVariable2: Integer;
  published
     property    Variable1: Integer read FVariable1 write FVariable1;
     property    Variable2: Integer read FVariable2 write FVariable2;
  end;

type
  TCBRecords     =  class(TCollection)
  private
     function    GetItem(Index: Integer): TCBRecord;
     procedure   SetItem(Index: Integer; Value: TCBRecord);
  public
     constructor Create;
     function    Add: TCBRecord;
     property    Items[Index: Integer]: TCBRecord read GetItem write SetItem; default;
  end;

implementation

function TCBRecords.Add: TCBRecord;
begin
  result:=TCBRecord(inherited Add);
end;

function TCBRecords.GetItem(Index: Integer): TCBRecord;
begin
  result:=TCBRecord(inherited GetItem(Index));
end;

procedure TCBRecords.SetItem(Index: Integer; Value: TCBRecord);
begin
  inherited SetItem(Index, Value);
end;

constructor TCBRecords.Create;
begin
  inherited Create(TCBRecord);
end;

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

Anyways, it just provides a more tightly coupled way of managing same type objects, not to say that it could not have been done with TObjectList.


Russell



0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10742679
Example of use:

var  cbRecords: TCBRecords;
begin

  cbRecords:=TCBRecords.Create;
  with cbRecords.Add do
  begin
     Variable1:=10;
     Variable2:=20;
  end;
  Assert(cbRecords.Count = 1, 'Incorrect count');
  cbRecords[0].Free;
  Assert(cbRecords.Count = 0, 'Incorrect count');

  cbRecords.Free;
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10747003
Hi Shane

In the procedure I call I am just writing the info being held in the records to a stringrid
Following on from before:-

for RecordIndex:= 0 to (MyList.Count - 1) do
  ReadTCBRecordAndDoSomething(RecordIndex);

procedure ReadTCBRecordAndDoSomething(RecordIndex: integer);
begin
  Cells[Col1,Selected_Row] := MyList[RecordIndex].Value1;
  Cells[Col2,Selected_Row] := MyList[RecordIndex].Value2;
  Cells[Col3,Selected_Row] := MyList[RecordIndex].Value3;
  <etc>
  Inc(Selected_Row)
end

Im hoping this should loop through the TObjectList and write the values to the grid.
The issue is that it only ever seems to read the last record from the TObjectList,
whatever index value I use for MyList it contains the same data, the last record entered
into the list. Its almost like the last record is repeated at every index, like it overwrote
previous data for some reason.

Temp_CBRecord := TCBRecord.create;
while <Something> do
begin
  Temp_CBRecord.VALUE1  := IBQuery.FieldByName('VALUE1').AsString;
  Temp_CBRecord.VALUE2   := IBQuery.FieldByName('VALUE2').AsString;
  <etc>
  MyList.Add(Temp_CBRecord);
  IBQuery.next
end;

is where I populated the TObjectList.
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10747006
Thanks for that other info btw Russel, that was new to me so nice to learn.
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10751363
Where I create my Temp_CBRecord for populating my TObjectList, the only thing I can think about is that the reason it is displaying the same record is that I am over-writing previous records with the last one.

Am I using this incorrectly .. MyList.Add(Temp_CBRecord) .. and then deleting values when I go back round the loop again to create a new MyList.Add(Temp_CBRecord)
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10751379
Ok .. think Im definitely overwriting my TCBRecord everytime I populate my MyList .. I just assumed it would "add" the record to MyList and then let me create a new one over the top of it
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10751387
This is where the problem area is .. after a bit of debugging

Procedure TThisForm.Populate_MyList;
var
  Temp_CBRecord: TCBRecord;
begin
  Temp_CBRecord := TCBRecord.create;

  //dmAcc is a datamodule holding my TIBQuery IBQ_Cashbook
  with dmAcc, IBQ_Cashbook do  
  begin

     //Loop and add records to a certain date
    while (fieldbyname('ENTRY_DATE').AsDateTime < EndOfTheMonth(DTP_1Month.Date)) and not eof do  
    begin
      Temp_CBRecord.sCR_DR  := FieldByName('CR_DR').AsString;
      Temp_CBRecord.sDesc   := FieldByName('CR_DR_DESC').AsString;
      Temp_CBRecord.sReason := FieldByName('REASON').AsString;
      Temp_CBRecord.dAmount := FieldByName('AMOUNT').AsFloat;
      Temp_CBRecord.dCBDate := FieldByName('ENTRY_DATE').AsDateTime;
      Temp_CBRecord.sOrderNo:= FieldByName('ORDER_NO').AsString;

      MyList.Add(Temp_CBRecord);   //Overwriting previous records added to MyList every loop it seems.
      next
    end;
  end
end;
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10753764
I know Ive made an object just to hold data ...
Do you think maybe I would have been better just creating a record instead

Unless there is an easy solution Im not spotting in my n00bness
I presume I need a number of Temp_CBRecord 's .. but I dont know how many I will need   :o/
0
 
LVL 11

Expert Comment

by:shaneholmes
ID: 10753775
You just needed to move the following line down:

    Temp_CBRecord := TCBRecord.create;


Procedure TThisForm.Populate_MyList;
var
  Temp_CBRecord: TCBRecord;
begin
  //dmAcc is a datamodule holding my TIBQuery IBQ_Cashbook
  with dmAcc, IBQ_Cashbook do  
  begin
     //Loop and add records to a certain date
    while (fieldbyname('ENTRY_DATE').AsDateTime < EndOfTheMonth(DTP_1Month.Date)) and not eof do  
    begin
      Temp_CBRecord := TCBRecord.create;  //*************** create a record for each in table
      Temp_CBRecord.sCR_DR  := FieldByName('CR_DR').AsString;\
      Temp_CBRecord.sDesc   := FieldByName('CR_DR_DESC').AsString;
      Temp_CBRecord.sReason := FieldByName('REASON').AsString;
      Temp_CBRecord.dAmount := FieldByName('AMOUNT').AsFloat;
      Temp_CBRecord.dCBDate := FieldByName('ENTRY_DATE').AsDateTime;
      Temp_CBRecord.sOrderNo:= FieldByName('ORDER_NO').AsString;
      MyList.Add(Temp_CBRecord);   //Overwriting previous records added to MyList every loop it seems.
      next
    end;
  end
end;

Shane
0
 
LVL 15

Author Comment

by:mikelittlewood
ID: 10756333
geez .. silly mistake.

thanks for all your help!
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses
Course of the Month12 days, 20 hours left to enroll

777 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