16.7 Mehrseitiger Text
Den Abschluss der Druckthematik bildet ein Beispiel, das den Inhalt einer Textbox formatiert ausgibt und außerdem berücksichtigt, dass der Ausdruck mehrere Druckseiten lang sein kann. Das Programm lädt eine Textdatei in eine Textbox und druckt den Text aus. Zusammen mit Abschnitt 12.12.1, »Datei zum Öffnen wählen (OpenFileDialog)«, Abschnitt 12.12.2, »Datei zum Speichern wählen (SaveFileDialog)« und Abschnitt 18.4, »Die Zwischenablage«, haben Sie einen Startpunkt zur Entwicklung eines Texteditors.
Sehen wir uns nun den Programmcode zusammengefasst an – zunächst nur die Passagen, die keiner genaueren Erklärung bedürfen. Dazu gehört nicht der Ereignishandler des PrintPage-Ereignisses, den wir anschließend Zeile für Zeile behandeln. Der Einfachheit halber habe ich auf die komplette Fehlerbehandlung verzichtet.
'...\Drucken\Druck\Textdateien.vb |
Imports System.Drawing.Printing Public Class Textdateien Private Sub Neu_Click(sender As Object, e As EventArgs) Handles Neu.Click Textfenster.Text = "" Text = "Unbenannt" End Sub Private Sub Öffnen_Click(sender As Object, e As EventArgs) _ Handles Öffnen.Click Dim ofd As New OpenFileDialog() ofd.Filter = "Textdateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*" ofd.Title = "Öffnen einer Textdatei" If ofd.ShowDialog() = DialogResult.OK Then Textfenster.Text = IO.File.ReadAllText( _ ofd.FileName, System.Text.Encoding.Default) Text = ofd.FileName End If End Sub Private WithEvents doc As New PrintDocument() Private zuDrucken As String Private von, bis, nummer As Integer Private Sub Drucken_Click(sender As Object, e As EventArgs) _ Handles Drucken.Click Dim d As New PrintDialog() : d.Document = doc : d.AllowSomePages = True If d.ShowDialog() = DialogResult.OK Then doc.DocumentName = Text & " " & Now zuDrucken = Textfenster.Text Select Case d.PrinterSettings.PrintRange Case PrintRange.AllPages von = 1 : bis = d.PrinterSettings.MaximumPage Case PrintRange.SomePages von = d.PrinterSettings.FromPage : bis = d.PrinterSettings.ToPage End Select nummer = 1 doc.Print() End If End Sub Private Sub Einrichten_Click(sender As Object, e As EventArgs) _ Handles Einrichten.Click Dim d As New PageSetupDialog() : d.Document=doc : d.EnableMetric=True d.ShowDialog() End Sub Private Sub Seitenansicht_Click(sender As Object, e As EventArgs) _ Handles Seitenansicht.Click Dim p As New PrintPreviewDialog() : p.Document = doc Dim d As New PrintDialog() : d.Document = doc : d.AllowSomePages = True zuDrucken = Textfenster.Text von = 1 bis = d.PrinterSettings.MaximumPage nummer = 1 p.ShowDialog() End Sub ... End Class
Der Ereignishandler von PrintPage
Im PrintPage-Ereignishandler befindet sich die gesamte Steuerung des Druckvorgangs. Dazu gehören die Ermittlung der für den Textausdruck zur Verfügung stehenden Rechteckfläche und die Anzahl der Druckzeilen jeder Seite. Dabei darf die letzte Zeile der Seite nicht abgeschnitten werden. Zusätzlich soll jede gedruckte Dokumentenseite eine Kopfzeile mit dem Dateinamen enthalten und in einer Fußzeile die aktuelle Seitenzahl anzeigen.
Nach der Deklaration einiger lokaler Variablen, die innerhalb des Ereignishandlers benötigt werden, wird der Druckbereich des gesamten Ausdrucks festgelegt.
außen = e.MarginBounds
innen legt die Größe des Rechtecks fest, in dem der Text aus der Textbox ausgedruckt wird. Die Methode Inflate der Klasse Rectangle vergrößert/verkleinert eine Rechteckfläche. In unserem Fall subtrahieren wir Kopf- und Fußzeile.
innen = RectangleF.Inflate(außen, 0, –2 * ft.GetHeight(e.Graphics))
Die Anzahl der Zeilen muss in jedem Fall durch eine ganze Zahl beschrieben werden. Durch eine ganzzahlige Division erhalten wir die gerade passenden Zeilen. Alternativ können Sie die klassengebundene Methode Floor der Klasse Math verwenden.
Dim anzahlZeilen As Integer = innen.Height \ ft.GetHeight(e.Graphics)
Nun können wir den Ausdruck beginnen. Nur Seiten im gewünschten Bereich erscheinen. Deshalb wird der Ausdruck von einer If-Anweisung umschlossen.
If nummer >= von AndAlso zuDrucken.Length >= 0 Then ... End If
Der Ausdruck besteht aus drei Teilen. Zuerst wird der normale Text gedruckt. Es wird ein Formatierungsobjekt übergeben, damit kein Wort in der Mitte abgeschnitten wird.
form.Trimming = StringTrimming.Word e.Graphics.DrawString(zuDrucken, ft, Brushes.Black, innen, form)
Danach werden Kopf- und Fußzeilen gedruckt. Die Kopfzeile wird zentriert ausgegeben.
form.Alignment = StringAlignment.Center e.Graphics.DrawString(Text, ft, Brushes.Black, außen, form)
Die Fußzeile wird rechtsbündig formatiert.
form.LineAlignment = StringAlignment.Far e.Graphics.DrawString("S " & nummer, ft, Brushes.Black, außen, form)
Nachdem der Text gedruckt worden ist (oder der Ausdruck übersprungen wurde), wird er aus dem zu druckenden Resttext entfernt. Dadurch kann jede Seite so tun, als beginne sie am Anfang des Textes. Korrespondierend zum Ausdruck wird wortweise formatiert. Die Anzahl Zeilen, die auf die Seite passen, wird mit MeasureString ermittelt.
form.Trimming = StringTrimming.Word e.Graphics.MeasureString(zuDrucken,ft,innen.Size,form,zeichen,zeilen) zuDrucken = zuDrucken.Substring(zeichen)
Danach wird die Seitenzahl erhöht und zur nächsten Seite fortgeschritten. Wenn der Ausdruck übersprungen wurde, druckt die Methode Druck die nächste Seite. Auf diese Weise wird die Auslösung des PrintPage-Ereignisses vermieden und wird keine leere Seite ausgegeben. Wurde eine Seite ausgegeben, wird in HasMorePages gespeichert, Gibt an, ob weitere Seiten folgen.
nummer += 1 If nummer – 1 < von Then Druck(sender, e) Else e.HasMorePages = zuDrucken.Length > 0 AndAlso nummer <= bis End If
Damit ist das PrintPage-Ereignis fertig implementiert. Der Programmcode sieht vollständig wie folgt aus:
'...\Drucken\Druck\Textdateien.vb |
Imports System.Drawing.Printing Public Class Textdateien ... Private Sub Druck(ByVal sender As Object, ByVal e As PrintPageEventArgs) _ Handles doc.PrintPage Dim ft As Font = Textfenster.Font Dim form As New StringFormat() Dim außen, innen As RectangleF Dim zeichen, zeilen As Integer ' umschreibendes Rechteck des Druckbereichs (mit/ohne Kopf+Fußzeile) außen = e.MarginBounds innen = RectangleF.Inflate(außen, 0, –2 * ft.GetHeight(e.Graphics)) ' Anzahl vollständig passender Druckzeilen ermitteln und Höhe anpassen Dim anzahlZeilen As Integer = innen.Height \ ft.GetHeight(e.Graphics) innen.Height = anzahlZeilen * Textfenster.Font.GetHeight(e.Graphics) ' Seite drucken (automatisch abgeschnitten durch form) If nummer >= von AndAlso zuDrucken.Length >= 0 Then ' zu langen Text hinter dem letztem vollständig passenden Wort kappen form.Trimming = StringTrimming.Word e.Graphics.DrawString(zuDrucken, ft, Brushes.Black, innen, form) ' Dateiname in der Kopfzeile anzeigen form.Alignment = StringAlignment.Center e.Graphics.DrawString(Text, ft, Brushes.Black, außen, form) ' Seitennummer in der Fußzeile anzeigen form.LineAlignment = StringAlignment.Far e.Graphics.DrawString("S " & nummer, ft, Brushes.Black, außen, form) End If ' gedruckten Text aus Drucktext nehmen; zeichen/zeilen: Größe der Seite form.Trimming = StringTrimming.Word e.Graphics.MeasureString(zuDrucken,ft,innen.Size,form,zeichen,zeilen) zuDrucken = zuDrucken.Substring(zeichen) nummer += 1 If nummer – 1 < von Then Druck(sender, e) Else e.HasMorePages = zuDrucken.Length > 0 AndAlso nummer <= bis End If End Sub End Class
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.