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.