Ein Beispiel für Fall 1 wären zum Beispiel zwei Listen mit allen Aufträgen und allen Angeboten, die je für einen Kunden erzeugt wurden, und zwar innerhalb einer Liste. Erst kommt die Liste mit den Aufträgen, dann die mit den Angeboten. Ein Beispiel für Fall 2 wäre eine Liste mit allen Aufträgen, die je Auftrag eine Tabelle mit allen Positionen enthält. Das hat man mit L&L bisher zwar auch hinbekommen, indem man in der Druckschleife Bedingungen (als Variable) gesetzt und dann wechselweise Auftragsdaten und -positionen übergeben hat, die jeweils innerhalb einer Tabelle in verschiedenen Datenzeilen saßen und auf die Darstellungsbedingungen reagierten, aber mit mehreren Tabellen geht das viel einfacher und auch eleganter. Und die Kunden verstehen es besser! Der gewaltige L&L-Designer lässt zwar vieles zu, aber auch bei uns im Haus sind schon Formulare entstanden, die zwar prächtig aussehen, aber kaum mehr zu durchschauen sind.
Ich habe mich jetzt aus aktuellem Anlass mit der Systematik beschäftigt, nachdem ich das lange vor mir hergeschoben habe. Dabei ist es total einfach. Und so geht es:
1. Schritt:
Üblicherweise haben List-Projekte eine Datenquelle, die alles mögliche sein kann, zum Beispiel ein Konglomerat aus Tabellendaten oder Arrays oder was auch immer. Bei Kreuz- und Verbundtabellen meldet man alle Tabellen an, die es im Projekt geben soll. Dabei ist wieder völlig wurscht, ob das echte Tabellen sind oder auch nur Arrays oder sonstwas. Das geschieht nach der Eröffnung des Jobs und dem Setzen der Optionen. Hier melde ich zwei Tabellen an, nämlich Angebote und Aufträge (Hinweis: Ich arbeite mit dem OEM-Zeichensatz, deshalb steht da oft ConvToAnsiCP()):
Code: Alles auswählen
LlDbAddTable(hJob,'','') // setzt alle Tabellen zurück
LlDbAddTable(hJob,ConvToAnsiCP('Auftraege'),'')
LlDbAddTable(hJob,ConvToAnsiCP('Angebote'),'')
2. Schritt:
Vor dem Aufruf des Designers müssen für alle Tabellen alle Felder bekannt sein. Das geschieht ganz normal mit LlDefineField() bzw. LlDefineFieldExt(). Der Einfachheit halber und weil man im Formular ohnehin alles mit Daten machen kann, was man will, übergebe ich hier alle Daten als Strings. Für den Designer befülle ich die Felder mit ihren Namen:
Code: Alles auswählen
LlDefineFieldStart(hJob) // einmalig
DbSelectArea('Auftraege')
For i := 1 to Fcount()
LlDefineFieldExt(hJob,'Auftraege.'+fieldname(i),fieldname(i),LL_TEXT,0)
Next
3. Schritt:
Die Druckroutine muss jetzt leicht abgewandelt werden, weil das Formular entscheidet (!), welche Daten gerade benötigt werden. Das erlaubt es, die Tabellen im Formular beliebig anzuordnen, also erst Aufträge und dann Angebote oder umgekehrt. Ich nehme einfach mal an, dass in beiden Tabellen der Zeiger auf dem ersten Datensatz steht und dass z.B. ein Scope gesetzt ist - auf Kundennummer.
Code: Alles auswählen
lPrint := .T.
Do While lPrint
cTableId := space(30)
LlPrintDbGetCurrentTable(hJob, @cTableId,30,.F.)
cTableId := trim(strtran(cTableId,chr(0),'')) // ACHTUNG: 0-terminierter String!
Do Case
Case cTableId = 'Auftraege'
DbSelectArea('Auftraege')
Do While !Eof()
* jetzt wie oben (leere Daten) verfahren, aber natürlich mit Daten
FelderDrucken(hJob) // siehe unten
DbSkip(1)
EndDo
* Angebote
EndCase
nRet:=LlPrintFieldsEnd(hJob)
Do While nRet=LL_WRN_REPEAT_DATA
nRet:=LlPrintFieldsEnd(hJob)
Enddo
Ff !(nRet = LL_WRN_TABLECHANGE .or. nRet=LL_WRN_REPEAT_DATA)
lPrint := .F.
Endif
Enddo
* Druck abschließen, wie gehabt
Die kleine Prozedur "FelderDrucken(hJob)" löst den Druck der jeweiligen Zeile aus, wie auch im normalen Druck:
Code: Alles auswählen
Procedure FelderDrucken(hJob)
nRet:=LlPrintFields(hJob)
Do While nRet=LL_WRN_REPEAT_DATA
LlPrint(hJob)
nRet := LlPrintFields(hJob)
Enddo
RETURN
Im Formular steht jetzt eine neue Auswahl "Berichtscontainer" zur Verfügung. In diesem wählt man alle Tabellen, die gedruckt werden sollen, wobei ein Assistent bei der Auswahl der Felder hilft. Hier wird auch die Anordnung der Tabellen gewählt. Sie liegen im Designer "übereinander", werden aber in der gewählten Reihenfolge gedruckt. Man hat fantastische Layoutmöglichkeiten, und ich habe schon ziemlich geile Formulare damit gebaut. Wer Fragen dazu hat - feel free!