Grafische Programmierung: Drucken

Wollen wir von unserem Programm etwas ausdrucken, so müssen wir uns ebenfalls mit der grafischen Programmierung auseinandersetzen. Das benötigte PrintDocument-Objekt (welches ein unsichtbares Steuerelement ist und im Werkzeugkasten ausgewählt werden kann) befindet sich hierbei im Namensraum System.Drawing.Printing.
Natürlich könnten wir einfach nur unser Dokument ausdrucken, doch wir wollen unserem Benutzer auch die Auswahl seines Druckers und deren Einstellungen ermöglichen. Hierfür benötigen wir den Dialog PrintDialog (System.Windows.Forms Namensraum). Über die Eigenschaften AllowCurrentPage, AllowSelection und AllowSomePages können wir die Auswahl der Felder „Aktuelle Seite“, „Markierung“ und „Seiten: x“ aktivieren bzw. deaktivieren. Der Standardwert der Eigenschaften ist false, wodurch die Felder deaktiviert sind. Über die Eigenschaft Document legen wir das Objekt des zu druckenden Dokuments (PrintDocument) fest. Die Eigenschaft UseEXDialog sollte auf true gesetzt werden, da es andernfalls Probleme mit der Darstellung des Dialogs auf x64-Betriebssystemen geben kann. Dieses Problem wurde bereits von Microsoft bestätigt.
Nun wollen wir uns die Klasse PrintDocument etwas genauer anschauen: Die Eigenschaft DocumentName legt den Namen des Dokuments fest (dieser wird z. B. beim Drucken auf dem Display des Druckers oder in der Druckerwarteschlange des Computers angezeigt). Die Eigenschaft OriginAtMargins legt fest, ob sich die Positionsangaben beim Zeichnungsvorgang auf die linke obere Ecke des Blattes (Wert false) oder die linke obere Ecke der Seitenränder (Wert true) bezieht. Die Funktion Print() startet den Druckvorgang. Die PrintDocument-Klasse besitzt drei wichtige Ereignisse: BeginPrint, EndPrint und PrintPage. BeginPrint tritt auf bevor der eigentliche Druckvorgang beginnt und somit direkt nach dem Aufruf der Print()-Funktion. EndPrint tritt auf nachdem der Druckvorgang abgeschlossen ist. Beiden Ereignissen werden PrintEventArgs als Event-Argumente übergeben. Hierbei können wir über die Eigenschaft Cancel den Druckvorgang abbrechen oder abfragen, ob dieser abgebrochen wurde. Das PrintPage-Ereignis löst aus, sobald eine Seite gedruckt werden soll. Hier werden Event-Argumente der Klasse PrintPageEventArgs übergeben. Auch hier gibt es die Eigenschaft Cancel. Die Eigenschaft Graphics stellt, wie beim Paint-Ereignis auch, das Grafik-Objekt zur Verfügung, welches wir zum Zeichnen benötigen. Mit der Eigenschaft HasMorePages können wir festlegen, ob noch eine weitere Seite gedruckt werden soll (z. B. weil der Inhalt nicht auf eine Seite passt). Ist dieser Wert gesetzt, so wird die Ereignis-Funktion des PrintPage-Events erneut aufgerufen.
Doch wie erhalten wir die Information wie groß die Seite bzw. der dazugehörige Druckbereich ist? Hierfür gibt es die Eigenschaften PageBounds und MarginBounds. PageBounds enthält die Größe des Papiers. MarginBounds enthält hingegen die Breite und Höhe des Druckbereichs und die Position der Seitenränder. Dabei geben beide Eigenschaften ein Rectangle-Objekt zurück. Mit Hilfe dieser beiden Eigenschaften können wir z. B. errechnen, ob der gewünschte Inhalt auf eine Seite passt und ggf. HasMorePages auf true setzen. Das Drucken von Inhalten ist in einigen Umständen kompliziert. So erfordert es auch einige mathematische Kenntnisse und Berechnungen. Ein Beispiel hierfür ist, dass DrawString() die Zeichenkette immer fortlaufend zeichnet und somit ohne Zeilenumbruch. Wollen wir jedoch einen mehrzeiligen Text ausdrucken, so ist es erforderlich zu prüfen, wie viel von dem Text in eine Zeile passt und diesen dann aufzuteilen. Wir haben im Beispiel darauf jedoch verzichtet und versucht, das Beispiel so einfach wie möglich zu halten.

Form1.cs

private void buttonDrucken_Click(object sender, EventArgs e)
{
	if (printDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
	{
		// Druckauftrag senden (Ereignis PrintPage wird aufgerufen)
		printDocument1.Print();
	}
}

private void printDocument1_BeginPrint(object sender, PrintEventArgs e)
{
	if (MessageBox.Show("Wollen Sie den Druck-Auftrag wirklich starten?",
						"Drucken starten?",
						MessageBoxButtons.YesNo,
						MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
	{
		// falls nein gedrückt wird, Vorgang abbrechen
		e.Cancel = true;
	}
	else
		buttonDrucken.Enabled = false;
}

private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
	Point[] aKurvenPunkte = new Point[12];

	// siehe 11.2 Linien und Rechtecke
	e.Graphics.DrawRectangle(new Pen(Brushes.Red), new Rectangle(30, 20, 300, 150));
	e.Graphics.DrawLine(new Pen(Brushes.Blue), new Point(30, 20), new Point(330, 170));
	e.Graphics.DrawLine(new Pen(Brushes.Blue), new Point(30, 170), new Point(330, 20));

	// siehe 11.3 Ellipsen und Kurven
	e.Graphics.DrawEllipse(new Pen(Brushes.Red), new Rectangle(30, 220, 300, 150));
	aKurvenPunkte[0] = new Point(30, 220 + 75);
	for (int i = 1; i < 11; i++)
		aKurvenPunkte[i] = new Point(30 - 15 + (i * 30), 220 + 75 + (i % 2 == 0 ? 15 : -15));
	aKurvenPunkte[11] = new Point(30 + 300, 220 + 75);
	e.Graphics.DrawCurve(new Pen(Brushes.Blue), aKurvenPunkte);

	// siehe 11.4 Schrift
	e.Graphics.DrawString("Hallo Welt!", new Font(new FontFamily("Times"), 20, FontStyle.Bold | FontStyle.Italic), Brushes.Orange, new PointF(40, 420));

	// siehe 11.5 Bilder
	e.Graphics.DrawImage(Image.FromFile("Logo.png"), 80, 480, 180, 140);
}

private void printDocument1_EndPrint(object sender, PrintEventArgs e)
{
	if (!e.Cancel)
		MessageBox.Show("Die Testseite wurde erfolgreich gedruckt!");
	buttonDrucken.Enabled = true;
}
Download

LinksRechts