Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro Visual C++-CLI And The .NET 2.0 Platform (2006) [eng]-1

.pdf
Скачиваний:
70
Добавлен:
16.08.2013
Размер:
24.18 Mб
Скачать

508

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

There is no need to clear the on-screen buffer because the off-screen buffer will overwrite everything on the on-screen buffer. All the clearing of the on-screen buffer does is momentarily leave the screen empty before the off-screen buffer writes to it, which produces a flicker.

Caution If you forget to set the style to opaque, your image will flicker.

The last difference that I haven’t already discussed is the TranslateTransform() changes. Notice that you translate by one each time and not by “X”. The reason for this is that the same Graphics class stays active the entire time this program is running (unless the screen is resized). The same translation matrix is being used, so you only need to increment by one. When you reach the end of the screen, you need to translate all the way back in one big jump.

if (X < ClientRectangle.Width)

{

X++;

dbGraphics->TranslateTransform(1.0, 0.0);

}

else

{

X = -250; dbGraphics->TranslateTransform((float)-(ClientRectangle.Width+250), 0.0);

}

Figure 11-19 shows DoubleBuffering.exe sliding a happy face across the form. Unfortunately, this still image doesn’t show much of the sliding.

Figure 11-19. The sliding happy face

Printing

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 adapter 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.

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

509

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.

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.

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;

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

510

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

private:

System::Drawing::Printing::PrintDocument^ printDocument; System::Windows::Forms::PrintDialog^ printDialog; System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

void InitializeComponent(void)

{

this->printDocument =

(gcnew System::Drawing::Printing::PrintDocument()); this->printDialog = (gcnew System::Windows::Forms::PrintDialog()); this->SuspendLayout();

//

// printDocument

//

this->printDocument->PrintPage +=

gcnew System::Drawing::Printing::PrintPageEventHandler(this, &Form1::printDocument_PrintPage);

//

//printDialog

this->printDialog->Document = this->printDocument;

//Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(300, 300);

this->Name = L"Form1"; this->Text = L"Click to Print"; this->Paint +=

gcnew System::Windows::Forms::PaintEventHandler(this, &Form1::Form1_Paint);

this->Click +=

gcnew System::EventHandler(this, &Form1::Form1_Click); this->ResumeLayout(false);

}

#pragma endregion

private:

System::Void Form1_Click(System::Object^ sender, System::EventArgs^ e)

{

// Display Print dialog when mouse pressed

if (printDialog->ShowDialog() == Windows::Forms::DialogResult::OK)

{

printDocument->Print();

}

}

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

511

System::Void printDocument_PrintPage(System::Object^ sender, System::Drawing::Printing::PrintPageEventArgs^ e)

{

CreateHappyFace(e->Graphics); //Same call as Form1_Paint e->HasMorePages = false;

}

System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)

{

CreateHappyFace(e->Graphics);//Same call as printDocument_PrintPage

}

// Generic Happy Face Creator void CreateHappyFace(Graphics ^g)

{

Pen^ b4pen = gcnew 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);

delete b4pen;

}

};

}

The first thing I did when I created PrintHappyFace was drag and drop 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.) Then I added a PrintPage event handler to the PrintDocument. I examine the handler below.

This auto-generates 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 Click event of Form1, which displays the PrintDialog (see Figure 11-20) and gathers the user’s input on configuring the printer.

512

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

Figure 11-20. The Print 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() == System::Windows::Forms::DialogResult::OK)

When the DialogResult::OK is received, you call the documents Print() method, which then triggers a PrintPage event:

printdoc->Print();

The last thing to notice about the preceding example is the PrintPage event handler. The PrintPage event handler handles the printing of only one page at a time. 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. You must also keep track of where you left off printing, and when the next PrintPage event is triggered you then continue where you left off:

System::Void printDocument_PrintPage(System::Object^ sender, System::Drawing::Printing::PrintPageEventArgs^ e)

{

CreateHappyFace(e->Graphics);

e->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.

C H A P T E R 1 1 G R A P H I C S U S I N G G D I +

513

Summary

This has been another long chapter in which you covered a lot of ground. You started off with the basics of what GDI+ is. You created your third “Hello World” program—this time with a GDI+ flavor. You then moved on and examined many of the GDI+ classes, the most important being the Graphics class, from which all GDI+ functionality derives. You played with strings, fonts, and predrawn images and ended up with the basics of drawing your own image. Next, you covered the advanced topics: scrollable windows, optimizing, and double buffering. You ended the chapter by demonstrating that you can also use GDI+ to print to printers.

You should now have all the information you need to display your own images and no longer be restricted to drawing with the controls provided by Win Forms.

In the next chapter, you get to play with databases using ADO.NET. Along the way, you will look at some of the tools Visual Studio 2005 provides to work with databases.

C H A P T E R 1 2

■ ■ ■

ADO.NET and

Database Development

You’ve already looked at two of the four common methods of getting input into and out of your

.NET Windows applications: streams and controls. ADO.NET, which you’ll examine in detail in this chapter, is the third. In the next chapter, you’ll round it out with XML, the fourth and final common method. ADO.NET is a huge topic. In this chapter, you’ll learn about some of the more commonly used aspects of it.

When you’re implementing with ADO.NET, you’re dealing with data stores or, to use the betterknown term, databases. Most developers are going to have to deal with the database. If that thought frightens you, it shouldn’t, as ADO.NET has made the database an easy and, dare I say, fun thing to work with. The hard part now is no longer interfacing with the database, be it a 2-tier, 3-tier, or even n-tier architecture, but instead designing a good database. Hey—Visual Studio 2005 even works with you there!

The language of relational databases is still SQL. That doesn’t change with ADO.NET. If you don’t know SQL, then you might need to read up on it a little bit. However, for those of you who don’t know SQL, I made this chapter’s SQL code rudimentary, to say the least. SQL is a very powerful language, and most programmers should have at least some SQL knowledge. But don’t fret if you don’t, as the SQL you’ll find in this chapter isn’t important in your understanding of ADO.NET. What I’m basically trying to say in a roundabout way is that this chapter is about ADO.NET and not SQL.

This chapter starts by covering the basic concepts of ADO.NET. You’ll then move on to building, from scratch, a (very simple) database using Visual Studio 2005. Then, using this database, you’ll examine in detail the two methods provided by ADO.NET to access a database: connected and disconnected.

Those of you who have read my book Real World ASP.NET: Building a Content Management System (Apress, 2002) might find some of the material similar, as you’re going to be using the database I developed in that book.

What Is ADO.NET?

Databases are made up of tables, views, relationships, constraints, and stored procedures. They’re usually the domain of the database architects, designers, developers, and administrators. ADO.NET, on the other hand, is how application developers get their hands on these (meaning the tables, views, and so forth—not the architects and designers, though sometimes I’d like to get my hands on the designers . . .). With ADO.NET, it’s possible to keep these two diverse software developing worlds separate, letting the specialists in both fields focus on what they do best.

515

516 C H A P T E R 1 2 A D O . N E T A N D D A T A B A S E D E V E L O P M E N T

ADO.NET is a set of classes that encompasses all aspects of accessing data sources within the

.NET architecture. It’s designed to provide full support for either connected or disconnected data access, while using an Extensible Markup Language (XML) format for transmitting data when data transfer is required. Chapter 13 contains more details about XML, so don’t worry about it for now. Just think of ADO.NET as a programmer’s window into a data source, in this case the DVC_DB database.

The classes that make up ADO.NET are located primarily in two assemblies: System.Data.dll and System.Xml.dll. To reference these two assemblies, you need to either add the following two lines to the top of your application source:

#using <System.Data.dll> #using <System.Xml.dll>

or add a reference to these assemblies in the project’s Properties page.

The addition of the System.Xml.dll assembly is due to the heavy reliance on XML in the internals of ADO.NET and in particular the class XmlDataDocument.

Seven namespaces house all of ADO.NET’s functionality. These namespaces are described at a high level in Table 12-1.

Table 12-1. ADO.NET Namespaces

Namespace

Description

System::Data

Contains most of the classes that make up ADO.NET. The classes

 

found within this namespace are designed to work independently

 

of the type of data source used. The most important class in this

 

namespace is the DataSet class, which is the cornerstone of

 

disconnected data source access.

System::Data::Common

Contains the common interfaces used by each of the

 

managed providers.

System::Data::Odbc

Contains the classes that make up the ODBC managed provider,

 

which allows access to ODBC-connected databases such as

 

MySQL. The classes contained within this namespace are all

 

prefixed with Odbc.

System::Data::OleDb

Contains the classes that make up the OLE DB managed provider,

 

which allows access to databases such as Sybase, Microsoft Access,

 

and Microsoft SQL Server 6.5. The classes contained within this

 

namespace are all prefixed with OleDb.

System::Data::Oracle

Contains the classes that make up the Oracle managed provider,

 

which allows access to Oracle8i and later databases. The classes

 

contained within this namespace are all prefixed with Oracle.

System::Data::SqlClient

Contains the classes that make up the SQL Server managed

 

provider, which allows access to Microsoft SQL Server 7.0 and later

 

databases. The classes contained within this namespace are all

 

prefixed with Sql.

System::Data::SqlTypes

Contains classes for native data types associated with SQL Server.

 

 

Now that you have a basic understanding of what ADO.NET is, let’s take a small sidetrack from C++/CLI and see how to build a database using Visual Studio 2005.

C H A P T E R 1 2 A D O . N E T A N D D A T A B A S E D E V E L O P M E N T

517

Building a Database with Visual Studio 2005

Visual Studio 2005 is well equipped when it comes to the design and development of Microsoft SQL Server databases. It provides the functionality to create databases, tables, views, stored procedures, and many other features.

The starting point of all database utilities is Server Explorer. Select Server Explorer from the View menu to open it (see Figure 12-1). You will find your database in the Data Connections folder just above the Servers folder.

Figure 12-1. Server Explorer

Visual Studio 2005 provides Microsoft SQL Server databases with much of the functionality that comes with SQL Enterprise Manager. On the other hand, all the other database types are mostly restricted to viewing and editing records. This book focuses on Microsoft SQL Server and covers the functionality provided by Visual Studio 2005. If you are developing using any other database, much of the first part of this chapter will not help you because you will have to use the database maintenance tools provided by your database.

Tip If you don’t currently have a database installed on your system, I recommend that you install the MSDE 2000 database server or SQL Server 2005 Express. These databases are stripped-down versions of Microsoft SQL Server, and with either you’ll get a good feel for the functionality provided by Visual Studio 2005. Plus, you can always uninstall it later and use the database of your choice.

There is nothing stopping you from building your Microsoft SQL Server databases outside of Visual Studio 2005, using the SQL Enterprise Manager, for example, and then adding the database to Server Explorer. Doing this is beyond the scope of this book, however.

Now you’ll build your own simple content management database so that you can explore ADO.NET with intimate knowledge of its architecture, instead of as a black box as you would if you were using one of the preinstalled databases provided with Microsoft SQL Server.