FastReport Tipps und Tricks: Formatierung

Aus GEVITAS
Wechseln zu: Navigation, Suche

1 Formatierung

1.1 Schrift-Farbe von Felder abhängig von der Fremdmenge

Wenn man die Schrift-Farbe von Felder abhängig von der Fremdmenge setzen will, kann man das im Ereignis


 procedure DetailPositionenOnBeforePrint(Sender: TfrxComponent);

z.B. so machen:

Am Anfang die Farbe auf den Standard setzen:

 memoPosMengeAuftrag.Font.Color := clBlack; 
 MemoPositionenBezeichnung.Font.Color := clBlack;          

Dann unten die gewünschte Farbe setzen, z.B. so:

 // Fremdmengen rot:  
 if  <Positionen."MengeFremd"> > 0   then
 begin
   memoPosMengeAuftrag.Font.Color := clRed;
   MemoPositionenBezeichnung.Font.Color := clRed;          
 end;


1.2 Schrift-Farbe abhängig vom Alternativ-Kennzeichen

Wenn man die Farbe von Felder im Positionsbereich z.B. grau darstellen will, wenn es Alternativ-Positionen sind, kann man so einen Code in "OnBeforPrint" des Positionen-Bands verwenden:

 // Alternativ-Positionen hervorheben:
 // (Nicht beim Kapitel, das auch das Alternativ-Kennzeichen hat!)
 if (<Positionen."Alternativ_0_1"> = 1) and (<Positionen."PosNr"> > 0 ) then
 begin
   // Alternativ-Position kennzeichnen:
   memoPosGesBetrag.Font.Color := clWindowFrame;
   memoKapitelPosNr.Font.Color := clWindowFrame;  
   memoPosMengeAuftrag.Font.Color := clWindowFrame;  
   PositionenEinheit.Font.Color := clWindowFrame;  
   memoPosEinzelPreis.Font.Color := clWindowFrame;  
   memoPositionenRabattProz.Font.Color := clWindowFrame;  
       
   // Markierung mit " * " bei Alternativ-Position anzeigen
   MemoAlternativStern.Visible := True;  
   MemoAlternativStern2.Visible := True;
   MemoPositionenBezeichnung.Font.Style := 0; // fsItalic;                                                 
     
 end
 else
 begin
   // Position ist NICHT alternativ:
   memoPosGesBetrag.Font.Color := clWindowText;
   memoKapitelPosNr.Font.Color := clWindowText;  
   memoPosMengeAuftrag.Font.Color := clWindowText;  
   PositionenEinheit.Font.Color := clWindowText;  
   memoPosEinzelPreis.Font.Color := clWindowText;  
   memoPositionenRabattProz.Font.Color := clWindowText;  
 
   MemoAlternativStern.Visible := False;
   MemoAlternativStern2.Visible := False;
   MemoPositionenBezeichnung.Font.Style := fsBold;                                                 
 end;

Die hier gezeigten Namen der Memo-Felder müssen natürlich an die Namen in Ihrem Report angepasst werden.

Im Beispiel werden auch noch 2 Memo-Felder mit "*" verwendet, die vor und hinter dem Betragsfeld stehen und bei Alternativ-Positionen eingeblendet werden.

1.3 Farbe eines Bandes abwechselnd grau/weiß

Wenn man die Farbe eines Bandes (z.B. den Detail-Bereich, also die Positionen eines Auftrags) abwechselnd grau/weiß hinterlegen will, muss man ein bisschen in die Trickkiste greifen. Im OnBeforePrint-Ereignis des Bandes schreibt man diesen Code:

Variante 1
procedure DetailPositionenOnBeforePrint(Sender: TfrxComponent);
begin
  // Dieser Code wird ausgeführt, BEVOR das Positionen-Detail-Band ausgegeben wird.

  // Farbe abwechselnd weiß/grau:
  if <Line> mod 2 = 1 then  // Bei jeder GERAD-STELLIGEN Zeile!
  begin              
    TfrxBrushFill(DetailPositionen.Fill).BackColor := cl3dLight;  
    TfrxBrushFill(ChildDetailPositionen.Fill).BackColor := cl3dLight;  
  end                
  else
  begin              
    TfrxBrushFill(DetailPositionen.Fill).BackColor := clNone;
    TfrxBrushFill(ChildDetailPositionen.Fill).BackColor := clNone;  
  end;
end;

Der erste Trick ist die Zeile

  if <Line> mod 2 = 1 then  // Bei jeder GERAD-STELLIGEN Zeile!

<Line> ist eine System-Variable, die eine fortlaufende Zeilennummer (Datensatz-Nummer) zurückgibt, die FastReport einfach hochzählt. Der erste Datensatz hat einfach die Zeilennummer 1, der nächste 2 usw.

mod 2 ist eine Division und bringt den Rest der Divison zurück.


Variante 2

Wenn im Code allerdings eine Unterdrückung des Bandes unter bestimmten Umständen drin ist, funktioniert diese Methode oben nicht!

Wenn oben das Band wg. Kennzeichen unterdrückt wird, geht das nicht mehr, weil die Zeilen-Nummer ja eine Art von Datensatz-Nummer ist und irgendein Datensatz davon unterdrückt sein kann!


Das geht also nicht...

if <Line> mod 2 = 1 then  // Bei jeder GERAD-STELLIGEN Zeile!

...weil man ja nicht weiss, welche Zeile (=Datensatz) unterdrückt wurde.


Deshalb dieser Code:

procedure ddEinleitTermineDetailsOnBeforePrint(Sender: TfrxComponent);
begin
  // Drucken-Kennzeichen in den Terminen berücksichtigen:
  ddEinleitTermineDetails.Visible := True;  // Erst mal einschalten
  if ( <AuftragsKopf."StatusNr"> = 3 ) or ( <AuftragsKopf."StatusNr"> = 7 ) then
  begin
    // Angebot (3) und Anfrage (7):
    if <AuftragsTermine."DRUCKEN_ANG"> = 0 then
      ddEinleitTermineDetails.Visible := False;
  end
  else
  begin
    // Sonst:
    if <AuftragsTermine."DRUCKEN_AUFTR"> = 0 then
      ddEinleitTermineDetails.Visible := False;
  end;
 
  // Farbe abwechselnd weiß (=clNone) oder grau (cl3dLight):
 
  if ddEinleitTermineDetails.Visible then
  begin
    // Termin ist sichtbar:
    if TfrxBrushFill(memoBackgroundAuftrTermine.Fill).BackColor = clNone then
    begin
      TfrxBrushFill(memoBackgroundAuftrTermine.Fill).BackColor := cl3dLight;
    end
    else
    begin
      TfrxBrushFill(memoBackgroundAuftrTermine.Fill).BackColor := clNone;
    end;
  end;
end;

1.4 Gruppenkopf auf letzter Seite unterdrücken, wenn keine Daten mehr kommen

Man kann den Gruppenkopf einer Gruppe ganz gut dazu benutzen, eine Überschrift über die Positionen zu drucken, die auch auf jeder Seite wiederholt wird. Es kann nun aber vorkommen, dass die Positionen gerade an Ende einer Seite aufhören und auf der nächsten Seite trotzdem noch die Überschrift dazu gedruckt wird. Das sieht unschön aus. Dieser Artikel beschreibt, wie man das verhindert.


1.5 Report mit Sub-Detail-Band wird abgebrochen, wenn es keine Sub-Daten gibt

Ein Report hat folgende Bänder:

  • Master (Kopfdaten)
    • Details (Positionen)
      • SubDetails (Unterpositionen zu jeder Position)

Der Report wird wird jedoch abgebrochen, denn es keine Sub-Daten gibt!

Grund:

Man muss die Option "Drucken wenn Detail leer" auf dem Detail-Band einschalten!



1.6 Unterschiedliche Schriftarten in Auftrags-/Rechnungspositions-Texten

In den Textbausteinen eines Angebots, Auftrags oder einer Rechnung kommen die Texte in unterschiedlichen Schriftarten oder -Größen. Die Schriftart-Änderung im Report ist ohne Wirkung.

Grund
Die Schriftarten kommen aus den Texten selbst, also aus der Datenbank, nicht aus dem Report!
Es handelt sich hier ja um RTF-formatierte Texte. Die Schriftart/-Größe wird in den Stammdaten festgelegt. Das ermöglicht es, innerhalb des Textes Formatierungen vorzunehmen, z.B. Fettschrift.
Beim Einfügen eines solchen Textes wird die Formatierung aus den Stammdaten in die Positionen 1:1 übernommen.
Lösung
Man muss also die Schriftart in den Artikelstammdaten⇒Texte ändern!
Will man die Änderung testen, hat das zuerst keine Auswirkung! Grund: Änderungen in den Stammdaten werden nicht in die bestehenden Positionen übernommen, sonst würden dort eventuelle individuelle Änderungen unkontrolliert überschrieben. Man muss daher in den Positonen im Textbereich rechts unten auf den Sternchen-Button klicken, damit der Text neu aus den Stammdaten in die Position geholt wird.



1.7 Rahmen per Code setzen

Manchmal möchte man den Rahmen eines Objektes nur unter bestimmten Bedingungen setzen. Beispiel: Im Fuss eines Auftrags wird ja die Mehrwertsteuer ausgewiesen. Hat man nun einen Auftrag ohne Mehrwertsteuer, so sollen die Brutto-Felder (mit doppeltem Rahem unten) ausgeblendet werden und das Netto-Feld als Summenfeld den doppelten Rahmen bekommen. Beispiel:

FastReport Rahmen Code 01.png


Dazu kann man folgenden Code verwenden:

procedure FussPositionenOnBeforePrint(Sender: TfrxComponent);
begin
  // Ohne Mwst.: Mwst-Felder unterdrücken:
  if <AuftragsFuss."MwstBetrag"> = 0 then
  begin
    memoFussGesamtBrutto.Visible:= False;
    AuftragsFussMwstBetrag.Visible:= False;
    AuftragsFussMwstSatzProzent.Visible:= False;
    AuftragsFussGesamtBetragBrutto.Visible:= False;
    memoFussGesamtNetto.Text := 'Endbetrag in €';      // Ohne Mwst gibt's kein brutto/netto!
    memoFussGesamtNetto.Frame.Typ := ftBottom;         // Rahmen unten
    memoFussGesamtNetto.Frame.BottomLine.Style := fsDouble;         // Rahmen-Style "Doppelt"
  end;
end;


Hinweis
Das Textfeld memoFussGesamtNetto reicht bis zum rechten Rand des Formulars! Es liegt also teilweise unter dem Feld "NettoBetrag". Durch diesen Trick wird die Linie unten bis zum Betragsfeld rechts gezogen.


1.8 Positionsangaben im Code

Manchmal möchte man im Code ein Objekt verschieben.

Beispiele
  • Der Pauschal-Betrag in einem Angebot soll nach links eingerückt werden.
  • Ein Feld soll nach oben verschoben werden, wenn andere darüber ausgeblendet werden.

Dann kann man im Code die Position des Objektes festlegen:

Left
Legt die horizontale Position des Objektes fest, bezogen auf den linken Rand des Bands.
Top
Legt die vertikale Position des Objektes fest, bezogen auf das Band.

Beispiel:

  if <BestellFuss."Nettobetrag1"> = 0 then //JC//160209//
  begin
      RichFussStandardText.Top := 0.5 * fr1cm;
  end;

Dieser Code verschiebt ein Feld nach oben, und zwar auf 0,5 cm, bezogen auf das Band, auf dem es liegt.

"fr1cm" ist dabei eine Umrechnungs-Variable, die FastReport zur Verfügung stellt.

Der Grund: Alle Angaben von Positionen im Code wie Top, Left usw. werden in Pixeln gemacht. Dadurch ist eine sehr genaue und Hardware-unabhängige Positionierung möglich. Damit man nun die Angaben von Pixeln z.B. in cm einfach angeben kann, muss man nur die gewünschte cm-Anzahl mit fr1cm multiplizieren.

Im Beispiel oben wird das Textfeld auf die Top-Position (=von oben auf dem Band) auf 0,5 cm gesetzt.

  • Beachten Sie, dass das Kommata im Code der Punkt ist! Wenn man im Code also "0,5" schreibt, erhält man eine Fehlermeldung! Man muss "0.5" schreiben!
  • ACHTUNG! Wenn Sie die Top-Position im Code verschieben, kann das den Gesamt-Seitenzähler durcheinander bringen! Angenommen, es gibt ein Feldobjekt im Detail-Band, das im Editor auf der Feldposition 3 cm liegt und Sie verschieben es im Code auf "Top=0", dann kann es passieren, dass der Gesamt-Seitenzähler eine Seite mehr angibt als es in Wirklichkeit sind!!!

1.9 Top-Position im Code ändern

Manchmal möchte man die Top-Position von Objekten (also die "Zeile") im Code unter bestimmten Umständen ändern, z.B. Felder nach oben schieben, wenn die "Zeile" darüber ausgeblendet wurde.

In diesem Artikel wird ein Beispiel dazu beschrieben.


1.10 Feld reagiert nicht auf Änderung der Schriftgröße

Wenn man im Designer die Schriftgröße eines Feldes ändern und es wird trotzdem noch zu groß/zu klein/zu fett dargestellt, ist vermutlich ein sog. "Highlight" auf dem Feld gesetzt. Um das zu prüfen und zu entfernen, doppelklicken Sie auf das Feld und entfernen das Highlight.


1.11 Zahlen und Datum formatieren

1.11.1 Formatieren über die Objekt-Eigenschaften

Um Zahlen zu formatieren, klickt man mit der rechten Maustaste auf das Feld und wählt "Anzeigeformat". Neben den Standard-Formatierungen kann man dort auch individuelle Formate angeben:


Format-String Beschreibung, Beispiel
00 Formatiert die Zahl mit zwei Stellen. Wenn die Zahl einstellig ist, wird die leere Stelle mit "0" aufgefüllt. Anwendung z.B. für Tages- oder Monatszahlen. Beispiele "01", "02", "10", "12".
%0.0n Formatiert die Zahl ohne Nachkommastellen. Beispiele "1", "2", "10", "12".
%1.1f Formatiert die Zahl ohne Nachkommastellen. Beispiele "1,4", "2,5", "10,0", "12,0".
ddd dd.mm.yyyy Formatiert ein Datumsfeld mit Wochentag und Datum. Beispiel: "Mo 29.02.2016".

Diese Format-Strings können...

...im Objekt-Inspektor links unter "DisplayFormat" in das Eingabefeld "FormatString" eingegeben werden
oder
...mit der rechten Maustaste auf das Objekt klicken und "Anzeigeformat" wählen.
FastReport Format Datum 01.png

1.11.2 Formatieren in einem Textfeld

Wenn man ein Datum in einem Textfeld (Memo) formatieren will, kann man dazu die eingebaute Funktion FormatDateTime(Format-String,[Feld]) verwenden.

Im Format-String kann man die Formatierung festlegen.

Beispiel:

<b>[AuftragsKopf."AuftrNr"]</b>
[FormatDateTime(  'd-mmm-yyyy' ,  <AuftragsKopf."DruckDat">) ]

ergibt das Datum

6-Apr-2016

Das Ausschreiben des Monats verhindert Missverständnisse mit englisch- bzw. amerikanischen Ländern. Die Monats-Namen werden jedoch aus der Einstellung des Rechners geholt, d.h. ist der Rechner auf Deutsch eingestellt, werden auch die deutschen Monats-Namen verwendet!

Wenn es in einem Textfeld (Memo) mehrere eingebettete Felder gibt, kann man mit der rechten Maustaste - Anzeigeformat das gewünschte Feld auswählen...

FastReport Formatieren Uhrzeit.png

...und formatieren. In diesem Beispiel wird die Uhrzeit formatiert.

1.12 Monats-Namen aus Monats-Zahl

Da es keine eingebaute Funktion gibt, mit der man eine Monats-Nummer in einen Namen umwandelt, kann man sich eine eigene Funktion bauen:

procedure PageHeader1OnBeforePrint(Sender: TfrxComponent);
var
  Monatsnamen : Array[0..12] of String = ['FEHLT!','Januar','Februar','März','April','Mai','Juni','Juli',
                                          'August','September','Oktober','November','Dezember' ];
begin
    MemoTitel.Text := 'Statistik ' + Monatsnamen[<Monat>] + '  [Jahr]'
end;

Die Funktion geht davon aus, dass es eine Variable <Monat> gibt, in der die Zahl 1 bis 12 steht.

Anderes Beispiel
Hier wurde unter "Report⇒Variablen" eine Variable "Monatsname" deklariert.
Diese Variable wird für die Ausgabe des Monatsnamens verwendet.
Im BeforePrint-Ereignis des PageHeaders (Seitenkopf) steht:
procedure PageHeader1OnBeforePrint(Sender: TfrxComponent);
var
  Monatsnamen : Array[0..12] of String = ['FEHLT!','Januar','Februar','März','April','Mai','Juni','Juli',
                                            'August','September','Oktober','November','Dezember' ];
begin
   Set( 'Monatsname', '''' + Monatsnamen[  <Reisen."Monat"> ] + '''' );  // Setzt den Namen in die Variable. Zu beachten sind die einfachen Anführungszeichen '''' 
end;
Zu beachten sind die einfachen Anführungszeichen ' am Anfang und am Ende der Zuweisung.
Diese muss man angeben, damit FastReport weiß, dass es um einen Text geht.
Da FastReport die einfachen Anführungszeichen ' aber als Steuerzeichen benutzt, kann man die nicht einfach so in den Code schreiben!
Man muss deshalb '''' verwenden.
Das erste ' sagt aus, dass nun ein Text kommt.
Die beiden nächsten ' sagen, dass in dem Text ein ' benutzt werden soll.
Am Ende schließt das ' den Text ab.
Monatsnummer aus einem Datumsfeld
Um die Monatsnummer aus einem Datumsfeld zu bekommen, kann man die eingebaute Funktion MonthOf(Date) verwenden.
Wenn z.B. das Datum aus einem Datenbank-Feld kommt, sähe der Code so aus:
procedure PageHeader1OnBeforePrint(Sender: TfrxComponent);
var
  Monatsnamen : Array[0..12] of String = ['FEHLT!','Januar','Februar','März','April','Mai','Juni','Juli',
                                          'August','September','Oktober','November','Dezember' ];
   Monat : Integer;
begin
  Monat := MonthOf( <Statistik."Datum">  );
  MemoTitel.Text := 'Statistik ' + Monatsnamen[<Monat>] + '  [Jahr]'
end;

1.13 Text in Großbuchstaben

Manchmal möchte man, dass der Text eines Datenbank-Felder immer in GROSSBUCHSTABEN ausgegeben wird, auch wenn er in der Datenbank in Kleinbuchstaben gespeichert ist.

Beispiel:

Nach DIN 5008 muss der Ländername im Anschriften-Feld bei ausländischen Adressen in Großbuchstaben ausgegeben werden.

Um ein Feld in Großbuchstaben auszugeben, kann man Befehl

UpperCase( <Tabelle."Feldname"> ) )

verwenden.

Beispiel:

In einem Auftragsformular befindet sich ein Memo-Feld memoAnschrift, in das die Anschrift im Code eingefügt wird:

 // Anschriftenfeld zusammenstellen:
 memoAnschrift.Lines.Clear;
 memoAnschrift.Lines.Add( <AuftragsKopf."NameFirma"> );
 if <Ansprechpartner."Briefanrede"> >  then
   memoAnschrift.Lines.Add( <Ansprechpartner."Briefanrede"> );
 memoAnschrift.Lines.Add( <AuftragsKopf."Str"> );
 memoAnschrift.Lines.Add( <AuftragsKopf."PLZ"> + ' ' + <AuftragsKopf."Ort"> );
 memoAnschrift.Lines.Add( UpperCase( <Adresse."Landname"> ) );

In der letzten Zeile des Codes wird der Land-Name in Großbuchstaben ausgegeben.


1.14 Schriftattribute (Fett, unterstreichen ) in Feldern

Manchmal will man innerhalb eines Textfeldes (Memo) bestimmte Teile in Fett oder unterstrichen oder beides einsetzen.

Beipsiel:

Im Anschriftenfeld eines Auftrags soll die PLZ und der Ort fett-unterstrichen sein.

Am Einfachsten macht man das über sog. "HTML-Steuerzeichen". Dieses kann man einfach in den Text einfügen.


Steuerzeichen Auswirkung
<b> Fettschrift ein
</b> Fettschrift aus
<u> Unterstreichen ein
</u> Unterstreichen aus
<i> Kursiv (Italic) ein
</i> Kursiv (Italic) aus
<sub>Text tiefstellen ein </sub>Text tiefstellen aus
<sup> hochstellen ein </sup> hochstellen aus
<font color> Schriftfarbe wählen. Beispiel: "Normaler Text <font color=red>Text in rot</font>, <font color="#FF8030">Text in orange</font>


Im konstanten Text-Feld
Wenn es dabei um einen konstanten Text geht kann man diese Steuerzeichen einfach in den Text schreiben.
Beispiel:
"Es gelten unsere <b>Allgemeinen Geschäftbedingungen</b> und bla bla..."


Im Code ein Textfeld (Memo ) füllen

Wenn man im Code ein Textfeld füllt (z.B. das Anschriften-Feld im Auftragskopf) muss man im OnBefore-Print-Ereignis des entsprechenden Bandes folgendes schreiben:


 // Anschriftenfeld zusammenstellen:
 memoAnschrift.Lines.Clear;

 memoAnschrift.Lines.Add( <AuftragsKopf."NameFirma"> );

 if <Ansprechpartner."Briefanrede"> >  then
   memoAnschrift.Lines.Add( <Ansprechpartner."Briefanrede"> );

 memoAnschrift.Lines.Add( <AuftragsKopf."Str"> );
 memoAnschrift.Lines.Add( '<b><u>' + <AuftragsKopf."PLZ"> + ' ' + <AuftragsKopf."Ort"> + '</b></u>' ); 
 
 memoAnschrift.Lines.Add( UpperCase( <Adresse."Landname"> ) );

Wichtig ist, dass man die Steuerzeichen in einfache Anführungszeichen setzt:

'<b><u>'


Hinweis
Im Memo-Feld muss dazu die Eigenschaft "AllowHTMLTags" auf "True" gesetzt werden!

GevitasFormPrint Memo HTML Tags True.png


Verwenden Sie diese Methode mit Bedacht und nicht bei großen Textfelder (z.B. AGB'S über mehrere Seiten)!
  • So formatierte Textfelder werden (wie RTF-Felder) beim Export in eine PDF-Datei von FastReport1) in Grafiken umgewandelt!
  • Das vergrößert die PDF-Datei u.U. immens!

1) Gilt für FastReport 5.0. Ab 2018 wird FastReport 6.0 benutzt, wo formatierte Texte als Vector-Textgrafiken exportiert werden.

2 Konstanten im Code

Deklararion von Konstanten: Das vereinfacht/Vereinheitlicht z.B. die Datumsformatierung.

Statt überall..

FormatDateTime( 'd.mmm yyyy',<AuftragsKopf."VA-VonDatum"> )

...macht man besser:

FormatDateTime( sDateFormat ,<AuftragsKopf."VA-VonDatum"> )

...damit man bei einer gewünschten Änderung nur eine Stelle ändern muss.

Im Code oben schreibt man dazu:


const
  sDateFormat = 'd.mmm yyyy';


3 Links