Rave - General
How do you create calculated Fields in Rave?
Most everyone knows that you can create calculated fields in Delphi and use those in your reports. However, those fields are also available to your visual form components such as DBGrids so it's not always a desirable option. Another problem is that you can't define calculated fields for memo or graphic field types. Here's a method to define calculated fields in Delphi that will only be available to your reports, won't impact the rest of your application and works fine for memo or graphic fields. (The example used demonstrates one solution for printing addresses where some of the lines may be blank and you don't want them printed. You could also do this using DataMirrors.)
First, define an OnGetCols event on your data connection component:
Delphi Example:
procedure TForm1.CustomerCXNGetCols(Connection: TRPCustomConnection); begin With Connection do begin DoGetCols; WriteField('FullAddress', dtMemo, 30, '', ''); end; { with } end;
C++Builder Example
void __fastcall TForm1::CustomerCXNGetCols(TRPCustomConnection *Connection) { Connection->DoGetCols(); Connection->WriteField("FullAddress", dtMemo, 30, "", ""); }
The call to DoGetCols would create the default columns (fields) that would have been created if you hadn't defined this event. The only step left for this event is to call WriteField to define the meta-information for each field that you want to define. See Tutorial 26 in the ReportPrinter Pro manual for detailed instructions on WriteField. Next you need to define the OnGetRow event for the same data connection component.
Delphi Example:
procedure TForm1.CustomerCXNGetRow(Connection: TRPCustomConnection); var Stream: TMemoryStream; Memo: TMemo; s1, s2: string; i1: integer; begin With Connection do begin DoGetRow; // get data for table fields For i1 := 0 to 3 do begin case i1 of 0: s2 := Table1.FieldByName('Company').AsString; 1: s2 := Table1.FieldByName('Addr1').AsString; 2: s2 := Table1.FieldByName('Addr2').AsString; 3: begin s2 := Table1.FieldByName('City').AsString; s2 := s2 + ', ' + Table1.FieldByName('State').AsString + ' ' + Table1.FieldByName('Zip').AsString; end; end; // case if s2 <> '' then begin if s1 = '' then begin s1 := s2; end else begin s1 := s1 + #13#10 + s2; end;// else end;// if end;// for Stream := TMemoryStream.Create; Memo := TMemo.create(self); try Memo.Text := s1; Memo.Lines.SaveToStream(Stream); Stream.Position := 0; WriteBlobData(Stream.Memory^, Stream.Size); finally Stream.Free; Memo.Free; end;// tryf end; { with } end;
C++Builder Example:
void __fastcall TForm1::CustomerCXNGetRow(TRPCustomConnection *Connection) { TMemoryStream* Stream; TMemo* Memo; AnsiString s1, s2; Connection->DoGetRow(); // get data for table fields for (int i1=0; i1 < 4; i1++) { switch (i1) { case 0: s2 = Table1->FieldByName("Company")->AsString; break; case 1: s2 = Table1->FieldByName("Addr1")->AsString; break; case 2: s2 = Table1->FieldByName("Addr2")->AsString; break; case 3: { s2 = Table1->FieldByName("City")->AsString; s2 = s2 + ", " + Table1->FieldByName("State")->AsString + " " + Table1->FieldByName("Zip")->AsString; } break; }// switch if (s2 != "") { if (s1 == "") { s1 = s2; }// if else { s1 = s1 + "\n" + s2; }// else }// if }// for Stream = new TMemoryStream(); Memo = new TMemo(this); try { Memo->Text = s1; Memo->Lines->SaveToStream(Stream); Stream->Position = 0; Connection->WriteBlobData(Stream->Memory, Stream->Size); } // try __finally { delete Stream; delete Memo; }// tryf }
Once again we need to execute the default behavior for this event by calling DoGetRow. Then we get the address information and store it in a string variable. We then write the data for our calculated field by calling WriteBlobData (since it is a memo field). See Tutorial 26 in the ReportPrinter Pro manual for detailed instructions on WriteBlobData and the other WriteXxxxData methods. That's pretty much it. You can add more calculated fields to your data connection by adding more calls to WriteField and WriteXxxxData in each of these events. As with custom connections, you must have your application running and the data connection must be set to visible for these fields to show up since the code you have written must be executable.