![]() |
Zwei Datensätze mit for-Schleife auf eine Seite drucken
Ich habe eine Liste von Kontakten. Jetzt will ich auf jede Seite zwei datensätze drucken:
Delphi-Quellcode:
Aber irgendwie gelingt es mir nicht. Sowie es im Moment ist, druckt er mir nur die Hälfte, die dafür aber teilweise doppelt und dreifach. Wobei die Seitenzahl aber stimmt.
for i := 0 to FContactList.Count - 1 do
begin PrintAllContactsHeader(Printer.Canvas); PrintAllContactsFooter(Printer.Canvas, Printer.PageNumber); PrintAllFirstContact(Printer.Canvas, FContactList.Items[(i div 2)]); PrintAllSecondContact(Printer.Canvas, FContactList.Items[((i + 1) div 2)]); Inc(PageNumber); if PageNumber mod 2 = 0 then begin Printer.NewPage; end; end; |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Das ist auch kein Wunder, denn du nutzt ja jeweils die Indizes i div 2 und (i + 1) div 2. Jetzt schauen wir mal:
i = 0: Index 1 = 0 div 2 = 0, Index 2 = 1 div 2 = 0 i = 1: Index 1 = 1 div 2 = 0, Index 2 = 2 div 2 = 1 Du hast also schon da den Eintrag 0 dreimal gedruckt. ;-) Dadurch, dass du immer zwei auf einmal druckst, trotzdem aber alle Einträge durchgehst, klappt das nicht. Du hast zwei Möglichkeiten. Entweder du halbierst die Anzahl der Schleifendurchläufe oder du springst bei jedem zweiten heraus. Ich bevorzuge ersteres. Jetzt mal richtig:
Delphi-Quellcode:
// EDIT:
for i := 0 to (FContactList.Count - 1) div 2 do
begin PrintAllContactsHeader(Printer.Canvas); PrintAllContactsFooter(Printer.Canvas, Printer.PageNumber); PrintAllFirstContact(Printer.Canvas, FContactList.Items[i * 2]); if i * 2 + 1 < FContactList.Count then // Wenn Schluss ist, brauchts keine neue Seite usw. mehr begin PrintAllSecondContact(Printer.Canvas, FContactList.Items[i * 2 + 1]); Inc(PageNumber); // Evtl. nicht mehr nötig Printer.NewPage; end; end; Warum eigentlich genau zwei pro Seite? Ist die Größe der Einträge fest, so das nie mehr draufpassen? Sonst wäre es vielleicht sinnvoller jeweils so viele wie möglich draufzusetzen. Mit einer while-Schleife ließe sich das dann bei einem dynamischen Layout recht einfach umsetzen. |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Das Problem ist, ich habe ein Feld das in der Höhe variabel ist. Und es ist mir bisher noch nicht gelungen den Abstand zum nächsten Datensatz zu errechnen. Hinzukommt, dass man dann noch berücksichtigen müsste, was passiert, wenn ein Datensatz nicht mehr ganz auf eine Seite passt? Das würde das ganze ziemlich verkomplizieren. So habe ich genug Luft.
Er druckt eine Seite zu viel und die ist leer. |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Das liegt daran, dass du (wie in deinem vorherigen Quelltext) immer eine neue Seite aufmachst, egal ob noch Daten folgen. ;-)
Die Höhe kann man eigentlich recht gut berechnen, ich habe mir seinerzeit eine Routine geschrieben, die das übernommen hat. So habe ich eine recht komplexe Druckfunktion realisiert. |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Ich drucke jede Zeile einzeln mit einer Funktion, die mir die nächste Höhe zurück gibt. Leider noch nicht dynamisch. Ich müsste es noch hinbekommen, dass nict die einzelne Zeilwirklich gedruckten Zeilenenhöhe zurückgegebn wird, sondern die tatsächliche Höhe der wirklich gedruckten Zeilen. Das werde ich heute Abend, wenn ich wieder zu Hause bin mal vorstellen.
Zitat:
|
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
So geht es:
Delphi-Quellcode:
Aber wie würde das ganze für drei Datensätze auf einer Seite aussehen?
if i * 2 + 1 < FContactList.Count then // Wenn Schluss ist, brauchts keine neue Seite usw. mehr
begin PrintAllSecondContact(Printer.Canvas, FContactList.Items[i * 2 + 1]); if i * 2 + 1 <> FContactList.Count - 1 then Printer.NewPage; end; |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Getippt:
Delphi-Quellcode:
const SetsPerPage = 2;
for i := 0 to (FContactList.Count - 1) div SetsPerPage do begin PrintAllContactsHeader(Printer.Canvas); PrintAllContactsFooter(Printer.Canvas, Printer.PageNumber); for j := 0 to SetsPerPage - 1 do begin if (i * SetsPerPage + j) = FContactList.Count then break; // Abbrechen, wenn keine Datensätze mehr vorhanden PrintAllContact(j, Printer.Canvas, FContactList.Items[i * SetsPerPage + j]); end; if i <> (FContactList.Count - 1) div SetsPerPage then Printer.NewPage; // Wenn es nicht der letzte Durchlauf ist, neue Seite end; |
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Und wo ist die Positionsangabe? man müsste die Seite ja jetzt dritteln? Ich gucke mir das mal an.
|
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Dafür wird der Funktion PrintAllContact jetzt die Position angegebenen an der der Datensatz gedruckt werden soll ;)
Code:
PrintAllContact[b][color=#DF0000](j,[/color][/b] Printer.Canvas, FContactList.Items[i * SetsPerPage + j]);
|
Re: Zwei Datensätze mit for-Schleife auf eine Seite drucken
Die Frage ist ja wie das Zeichnen der Datensätze selbst geht. Ich habe dafür selbst was gebastelt, da wusste ich noch nicht, dass es da vieles auch schon auf API-Ebene gibt. Der Quelltext ist ururalt, da habe ich noch nicht lange programmiert, aber funktioniert hat er.
Delphi-Quellcode:
GetMultilineTextRect bricht den Text um und gibt die Zeilen zurück. GetItemHeight berechnet die Höhe des gesamten Eintrags, es geht hier um mehrere Spalten einer ListView (frmMain.lvwList).
function TPrinterObject.GetMultilineTextRect(Width: Integer;
Text: String): TStringList; var TextToAdd: String; begin Result:=TStringList.Create; if Printer.Canvas.TextWidth(Text)<=Width then Result.Add(Text) else while Length(Text)>0 do begin TextToAdd:=''; while ((Pos(' ',Text)>0) and (Printer.Canvas.TextWidth(TextToAdd + Copy(Text,1,Pos(' ',Text)-1)) < Width) or ((Pos(' ',Text)=0) and (Pos('/',Text)>0) and (Printer.Canvas.TextWidth(TextToAdd + Copy(Text,1,Pos('/',Text)-1)) < Width)) or ((Pos(' ',Text)=0) and (Printer.Canvas.TextWidth(TextToAdd + Text) < Width))) and (Length(Text)>0) do begin if Pos(' ',Text)=0 then begin if Pos('/',Text)=0 then begin TextToAdd:=TextToAdd + Text; Text:=''; end else begin TextToAdd:=TextToAdd+Copy(Text,1,Pos('/',Text)-1)+' / '; Delete(Text,1,Pos('/',Text)); Text:=Trim(Text); end; end else begin TextToAdd:=TextToAdd + Copy(Text,1,Pos(' ',Text)-1) + ' '; Delete(Text,1,Pos(' ',Text)); Text:=Trim(Text); end; end; if Trim(TextToAdd)<>'' then Result.Add(Trim(TextToAdd)) else begin while Printer.Canvas.TextWidth( TextToAdd+'a')<Width do begin TextToAdd:=TextToAdd+Text[1]; Delete(Text,1,1); end; Result.Add(Trim(TextToAdd)) end; end; end; procedure TPrinterObject.PrintMultilineText(uText: TStringList; uLeft, uTop: Integer); var i: Integer; begin for i:=0 to uText.Count-1 do Printer.Canvas.TextOut(uLeft, uTop + i*Printer.Canvas.TextHeight('A'), uText[i]); end; function TPrinterObject.GetLineCount(uText: String; uWidth: Integer): Integer; begin Result := Self.GetMultilineTextRect(uWidth,uText).Count; end; function TPrinterObject.GetItemHeight(uItem: Integer; uCols: array of Integer; ShortenLibrary: Boolean): Integer; var i, tmpLineCount: Integer; tmpString: String; begin Result := GetLineCount(frmMain.lvwList.Items[uItem].Caption,Round(0.9*uCols[0])); for i:=1 to High(uCols) do begin tmpString := frmMain.lvwList.Items[uItem].SubItems[i-1]; if (frmMain.fAppMetrics.GetBookListColType(frmMain.fDisplayMode,i) = colLibrary) and ShortenLibrary then begin if Pos('/',tmpString) > 0 then tmpString := Trim(Copy(tmpString,1,Pos('/',tmpString)-1)) else if Pos('(',tmpString) > 0 then tmpString := Trim(Copy(tmpString,1,Pos('(',tmpString)-1)); end; tmpLineCount := GetLineCount(tmpString, Round(0.9*uCols[i])); if Result < tmpLineCount then Result := tmpLineCount; end; Result := Result * Printer.Canvas.TextHeight('Aj'); end; Die neue Version dieses Quelltextes kann ich nicht posten, da es sich um ein kommerzielles Produkt handelt, aber von der Funktionsweise her ist der ähnlich, nur deutlich optimiert und sauberer geschrieben. Aber eben auch viel umfangreicher und produktspezifischer, deshalb würde der wohl auch nicht viel bringen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz