Blocksatz mit Printer()->Canvas
-
Ich möchte Textausgaben auf einem Drucker mit Printer()->Canvas->TextOut() im Blocksatz ausgeben. Kennt jemand eine Möglichkeit, um eine solche Ausgabe zu erzeugen? Vielleicht gibt es eine Komponente auf dem Markt?
Vielen Dank für eure Hilfe!
-
Hallo!
Ich würde das so angehen:
Ersteinmal die Breite für den Blocksatz festlegen.
Ne Schriftart auswählen.Dann mittels Printer()->Canvas->TextWidth("blahblah") sehen, wie breit der String ist - und ggf. mit Leerzeichen auffüllen (bevorzugt dort, wo schon Leerzeichen sind) - und wenn die Breite annähernd passt, druckst dus aufs Papier.
Und das machst du dann für alle Strings, die du hast.
...oder du nimmst ne Report-Komponente, die das alles schon kann...
tschüss
Robert
-
Hier ein Ansatz einmal unter Verwendung der WinAPI-Funktion SetTextJustification() und einmal ganz ohne API, also ggf. auch unter Linux/Kylix verwendbar.
'Blocksatz' wird im Englischen übrigens einfach als justified oder fully justified bezeichnet.//--------------------------------------------------------------------------- void __fastcall TForm1::JustifiedTextOut(TCanvas *canv, TRect rect, String text) { String line = ""; int line_nr = 0; // Zeilennummer (der Ausgabe) int line_spacing = 2; // Zeilenabstand in Pixeln int space_count = 0; // Leerzeichen mitzählen für SetTextJustification // Liste der einzelnen Wörter erstellen, ein einfaches Array würde es // auch tun, aber TStringList ist ja so bequem :-) TStringList *list = new TStringList(); list->Delimiter = ' '; list->DelimitedText = text; int X = rect.Left; int Y = rect.Top; int indx = 0; // Index in der Wortliste while (indx < list->Count) { // Zeile mit Worten füllen, bis Breite der Zeichenfläche erreicht while (canv->TextWidth(line) <= rect.Width()) { if (indx < list->Count) { line += list->Strings[indx++] + " "; space_count++; } else { space_count = 0; break; } } // wenn Breite überschritten, letztes Leerzeichen und ggf. letztes Wort löschen while (canv->TextWidth(line) > rect.Width()) { // Leerzeichen am Ende löschen int pos = line.LastDelimiter(" "); line.Delete(pos, 1); space_count--; // ist durch das Löschen natürlich eins weniger // mit etwas Glück passt es jetzt ... if (canv->TextWidth(line) <= rect.Width()) break; else // ... ansonsten muss halt auch das letzte Wort der Zeile dran { // glauben, einschliesslich des davor stehenden Leerzeichens pos = line.LastDelimiter(" "); line.Delete(pos, line.Length() - pos + 1); indx--; // das gelöschte Wort soll ja in die nächste Zeile space_count--; // ist noch eins weniger } } // ermitteln des normalerweise frei bleibenden Raumes am Ende der Zeile int extraspace = rect.Width() - canv->TextWidth(line); #ifdef __linux__ //Linux- bzw. non-API-Variante // Zeile in einzelne Worte zerlegen TStringList *tmplist = new TStringList(); tmplist->Delimiter = ' '; tmplist->DelimitedText = line; // freien Platz gleichmässig auf die Zwischenräume (Leerzeichen) aufteilen int space_width = canv->TextWidth(" "); if (space_count > 1) space_width += (extraspace / space_count); // erstes Wort am Zeilenanfang ausgeben ... canv->TextOut(X, Y, tmplist->Strings[0]); // dann die restlichen Worte ... for (int i = 1; i < tmplist->Count; i++) { // ... jeweils versetzt um die Breite des vorigen Wortes plus // der Breite des (ggf. erweiterten) Leerzeichens X = X + canv->TextWidth(tmplist->Strings[i-1]) + space_width; // bei unrunden oder kurzen freien Zeilenenden zumindest die ersten Zwischen- // räume um jeweils 1 verbreitern, soweit die Pixelzahl des Endes reicht if (space_count > 1 && i < extraspace % space_count) X++; // an neu ermittelter Position ausgeben canv->TextOut(X, Y, tmplist->Strings[i]); } delete tmplist; X = rect.Left; #else // WinAPI-Version SetTextJustification(canv->Handle, extraspace, space_count); canv->TextOut(X, Y, line); SetTextJustification(canv->Handle, 0, 0); #endif // für nächste Zeile vorbereiten line_nr++; Y = rect.Top + (line_nr * canv->TextHeight(line)) + line_spacing; space_count = 0; line = ""; } delete list; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { // freizulassende Ränder definieren TRect rect(10, 10, Image1->Canvas->ClipRect.Right - 20, Image1->Canvas->ClipRect.Bottom - 20); JustifiedTextOut(Image1->Canvas, rect, text_to_draw); } //---------------------------------------------------------------------------Wie gesagt, das ist nur ein Ansatz, da fehlt z.B. das Prüfen auf echte Zeilenumbrüche, Leerzeilen usw.
Na und etwas eleganter kann man das Ganze sicher auch noch gestalten.
-
Code aktualisiert.