ADO Database Delphi

Title: Accessing FieldObject Properties using Crystal Reports 8.0+ and Automation
Question: The documentation from Crystal Reports regarding automation is geared towards Visual Basic and does not work when trying to access the FieldObjects properties in Delphi.
Answer:
When using automation for Crystal Reports 8.0 and higher through Delphi, it is possible to alter field positions, sizes, etc. through the code. Unfortunately the help instructions offered by Seagate do not accurately describe the process in Delphi.
Below is an example of how to handle this. NOTE: For instructions on how to connect to Crystal Reports using automation, see my previous article - (ID 2159) Using Automation with Crystal Reports and Delphi.
This example assumes you have setup the sample application in my previous article, and have added the following components to the form:
CrystalApp: TApplication;
CrystalRpt: TCrReport;
CrystalView: TCRViewer;
procedure TForm1.ChangeFieldPositions;
var
Field_Left: integer;
Field_Top: integer;
Field_Width: integer;
RptObjs: IReportObjects;
FldObj: IFieldObject;
begin
// Get the info for a field in a particular section
RptObjs := CrystalRpt.Sections.Item[3].ReportObjects;
FldObj := IFieldObject(IReportObject(RptObjs.Item[1]));
Field_Left := FldObj.Left;
Field_Top := FldObj.Top;
Field_Width := FldObj.Width;
end;
This is an extremely simple procedure that doesn't do anything but store the Left, Top, and Width values for the first field in section three.
Unfortunately I haven't yet come up with a method of relating a particular section to the actual section in the Crystal Report. I.E. I can't say for sure that Sections.Item[3] is the Detail section or that Sections.Item[1] is the Report Heading section. Also, these values would change according to the complexity (and number of sections) of your report. However if your report structure will remain static, then you should be able to determine these values through testing.
The fields work a similar way to the sections, and it is a matter of testing to relate a field to a particular RptObjs.Item. One difference from the sections though is that fields appear to be read in reverse, where Field 1 is actually the last field entered into the report. Again I can't say for sure since I haven't thoroughly tested this or come up with a better method of finding fields. There is one thing to note though, RptObjs are not only Database Fields, they can be Text Fields, Lines, Formula Fields, etc. I suggest using the FieldObject.Kind property to test whether the field in question is of the type you desire.
To demonstrate this, here is another function that iterates through all the fields in a given section and returns the values of the text fields in a string list. NOTE: All fields and sections access is 1-based.
function TForm1.ShowFieldPositions: TStringList;
var
I: integer;
RptObjs: IReportObjects;
FldObj: IFieldObject;
TextObj: ITextObject;
begin
// Create the TStringList Object
Result := TStringList.Create;

// Iterate thorugh section 2 and store all the text field values in the list
RptObjs := CrystalRpt.Sections.Item[2].ReportObjects;
for I := 1 to RptObjs.Count do
begin
FldObj := IFieldObject(IReportObject(RptObjs.Item[I]));
// Test to see if its a Text Object
if FldObj.Kind = crTextObject then
begin
TextObj := ITextObject(FldObj); //Cast the FieldObject as a TextObject
Result.Add(TextObj.Text);
end;
end;
end;
I hope this helps as this was a major hurdle for me, and I have to give credit to Crystal Decisions Developer Support for their assitance in figuring this out.