Managed C++ and .NET Development: Visual Studio .NET 2003 Edition

I'll finish off this discussion of GDI+ by showing that you aren't restricted to the display adapter when it comes to GDI+. As I've been suggesting throughout the chapter, GDI+ is device independent, so in theory you should be able to draw using GDI+ to the printer. You know what? You can.

The printer is not as closely linked to the computer as the display adaptor is, so to get GDI+ to work, you need to somehow provide for this link between your system and the printer. GDI+ does this through the PrintDocument class, which you can find in the System::Drawing::Printer namespace.

You can configure the PrintDocument class using its members (see Table 11-16), but letting the PrintDialog handle this is much easier.

Table 11-16: Common PrintDocument Members

MEMBER

DESCRIPTION

DefaultPageSettings

Specifies the default settings to be used on all pages printed

DocumentName

Specifies the name of the document being printed

Print()

A method to start the printing process of a PrintDocument

PrintController

Specifies the print controller that maintains the print process

PrinterSettings

Specifies the printer that prints the document

In the example in Listing 11-20, you'll print the happy face I'm so proud of. First, you'll bring up the happy face using the normal Paint event handler method. Then you'll right-click to bring up the PrintDialog to print the happy face to the printer of your choice.

Listing 11-20: Printing a Happy Face

namespace PrintHappyFace { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; using namespace System::Drawing::Printing public __gc class Form1 : public System::Windows::Forms::Form { public: Form1(void) //... protected: void Dispose(Boolean disposing) //... private: System::Windows::Forms::PrintDialog * printDialog; private: System::Drawing::Printing::PrintDocument * printDocument; private: System::ComponentModel::Container * components; void InitializeComponent(void) { this->printDialog = new System::Windows::Forms::PrintDialog(); this->printDocument = new System::Drawing::Printing::PrintDocument(); // // printDialog // this->printDialog->Document = this->printDocument; // // Form1 // this->AutoScaleBaseSize = System::Drawing::Size(6, 15); this->ClientSize = System::Drawing::Size(300, 300); this->Name = S"Form1"; this->Text = S"Click to Print"; this->MouseDown += new System::Windows::Forms::MouseEventHandler(this,Form1_MouseDown); this->Paint += new System::Windows::Forms::PaintEventHandler(this,Form1_Paint); } private: System::Void Form1_MouseDown(System::Object * sender, System::Windows::Forms::MouseEventArgs * e) { // Display Print dialog when mouse pressed if (printDialog->ShowDialog() == DialogResult::OK) { printDocument->PrintPage += new PrintPageEventHandler(this, PrintPage); printDocument->Print() } } private: void PrintPage(Object * sender, PrintPageEventArgs *e) { CreateHappyFace(e->Graphics); //Same call as Form1_Paint e->HasMorePages = false; } private: System::Void Form1_Paint(System::Object * sender, System::Windows::Forms::PaintEventArgs * e) { CreateHappyFace(e->Graphics); //Same call as printDocument_PrintPage } private: // Generic Happy Face Creator void CreateHappyFace(Graphics *g) { Pen *b4pen = new Pen(Color::Black, 4); Rectangle rect = Drawing::Rectangle(25, 25, 250, 250); g->FillEllipse(Brushes::Yellow, rect); g->DrawEllipse(b4pen, rect); g->FillPie(Brushes::White, 100, 175, 100, 50, 0, 180); g->DrawPie(b4pen, 100, 175, 100, 50, 0, 180); rect = Drawing::Rectangle(100, 100, 25, 25); g->FillEllipse(Brushes::White, rect); g->DrawEllipse(b4pen, rect); rect = Drawing::Rectangle(175, 100, 25, 25); g->FillEllipse(Brushes::White, rect); g->DrawEllipse(b4pen, rect); } }; }

Just to prove that the same GDI+ code works for both the screen and the printer, I separated the code that generates the happy face into a method of its own that both the screen and print processes access.

First, look at the code as a whole and then I'll walk you through the highlights.

The first thing I did when I created PrintHappyFace is dragged and dropped a PrintDocument and a PrintDialog control to the form and then set the Document property of the PrintDialog to the newly created PrintDocument. (It will show up in the Document property drop-down box.)

This autogenerates all the code needed to create a PrintDialog and a PrintDocument and then links them together. I need to link the PrintDialog to the PrintDocument so that any configuration changes made to the printers through the PrintDialog get reflected in the PrintDocument.

Next, I added an event handler for the MouseDown event that displays the PrintDialog (see Figure 11-20) and gathers the user's input on configuring the printer.

Figure 11-20: The printer dialog box

If the user is happy and wants to complete the print process, he or she will click the OK button, which will return DialogResult::OK. If the user doesn't want to complete the print process, he or she will click the Cancel button and DialogResult::Cancel will be returned. I ignore this result in the example, but you might want to acknowledge the cancel. Printers are frequently on the opposite end of the office (I don't know how this is possible, but it seems to be always true), and walking to the printer and waiting for something cancelled could be aggravating to users.

if (pdialog->ShowDialog() == DialogResult::OK)

When the DialogResult::OK is received, you then need to delegate a handler to the PrintPage event. It is through the PrintPage event that you will actually be processing your GDI+ statements.

printdoc->PrintPage += new PrintPageEventHandler(this, PrintPage);

Finally, you tell the PrintDocument to start printing. My guess is that it triggers a PrintPage event.

printdoc->Print();

The last thing to notice about the preceding example is the event handler. The PrintPage event handler handles the printing of only one page. If you want to print more than one page, you need to set the HasMorePages property of the PrintPageEventArgs parameter passed to the PrintPage event handler to true.

void PrintPage(Object *sender, PrintPageEventArgs *e) { CreateHappyFace(e->Graphics); ppea->HasMorePages = false; // false means only one page will be printed. }

Notice that the exact same GDI+ code found in the CreateHappyFace() method is used for displaying to the screen and printing to the printer.

Категории