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

Microsoft Visual C++ .NET Professional Projects - Premier Press

.pdf
Скачиваний:
168
Добавлен:
24.05.2014
Размер:
25.78 Mб
Скачать

30

Part I

 

INTRODUCING VC++.NET

 

 

 

 

 

 

 

 

 

 

 

Constructor”);

 

 

 

 

 

 

 

 

}

 

 

 

 

 

};

 

 

 

 

 

 

 

class MyApp:public CWinApp

 

 

 

 

 

{

 

 

 

 

 

 

 

public:

 

 

 

Y

 

 

 

 

 

 

 

 

 

 

 

BOOL InitInstance()

 

 

 

 

{

 

L

 

 

 

 

 

 

F

 

 

 

 

 

MyWindow *MywindowObject = new MyWindow;

 

 

 

 

 

m_pMainWnd= MywindowObject;

 

 

 

 

 

M

 

 

 

 

 

 

ywindowObject ->ShowWindow(SW_SHOWNORMAL);

 

 

 

 

 

return TRUE;

 

 

 

 

 

}

 

 

 

 

};

 

E

 

 

 

 

MyApp MyAppObject;

T

 

 

 

 

 

A

 

The following are the steps to construct this sample application:

1. Include the header file afxwin.h, which contains the definitions for the core components of MFC, such as the definition of the CWinApp and

CFrameWnd classes.

2.Create the frame window for the application. To accomplish this, as a first step, a class named MyWindow is derived from the CFrameWnd class.

3.Invoke the Create function from within the constructor, as discussed earlier, to create the frame window and attach it to the application:

Create(NULL,”My Application Window”);

The first parameter of the Create function accepts the name of the Windows class. In the preceding code, NULL, which points to a null-ter- minated string, is passed. When you pass a NULL, the default values of

CFrameWnd are set.

The second parameter is the name of the window itself that is displayed on the title bar of the window. Here, My Application Window is assigned as the name of the window.

4.Define the application class itself. Hence, another class named MyApp is derived from the CWinApp class.

Team-Fly®

BASICS OF VC++.NET PROGRAMMING

Chapter 2

 

31

 

 

 

 

 

5.Override the InitInstance function and define the settings for your application. Here’s what needs to be done in the InitInstance function:

Create an instance of the window class of your application; here it is

MyWindow:

MyWindow *MywindowObject = new MyWindow;

MyWindowObject is the object of the MyWindow class and represents the current instance of the application.

Assign the window object that you created to the m_pMainWnd variable of the CWinApp class. m_pMainWnd always points to the main window of the application and thereby determines the lifetime of your application. This implies that only until the main window of the application is pointed to by m_pMainWnd, the application exists.

Invoke the ShowWindow function to display the window created. The ShowWindow function accepts the show state of the window, such as SW_SHOWNORMAL, that displays the window in the normal state (similar to the traditional window).

6. Instantiate the application class itself:

MyApp MyAppObject;

In this case, MyAppObject is the object pointing to the MyApp class.

The flowchart in Figure 2-7 depicts the sequence of events that occur after you execute an application, such as the sample application.

Type the code snippet preceding these steps and execute your application. Figure 2-8 displays the final output of the sample application.

Message Maps

You are now familiar with the classes that provide the foundation of your application. This section moves ahead to give you more details about messages and how to add the message-handling functionalities to your application.

From the earlier discussion, you know that Windows handles events by using message maps that handle the routing of messages to the appropriate message handlers. Taking this discussion further, messages are typically generated as a result of user-initiated actions. For example, when the user moves the mouse, Windows generates mouse-related messages; in this case, WM_MOUSEMOVE. In

32

Part I

INTRODUCING VC++.NET

 

 

 

Application executed

control passes to

CWinApp object constructed

control passes to

InitInstance function

Window object instantiated

control passes to

Constructor of the Window

class

Creates the window

control passes to

InitInstance function

m_pMainWnd initialized and the window is displayed

FIGURE 2-7 The sequence of events once an application is executed

BASICS OF VC++.NET PROGRAMMING

Chapter 2

 

33

 

 

 

 

 

FIGURE 2-8 The sample application

addition to this, every user interaction with the application, such as using the menu or the toolbar, also results in some messages. From the discussion, you can infer that there are different types of messages that your application needs to handle. Broadly, messages can be classified into three main categories:

Windows messages. All messages with the prefix WM_, except for the WM_COMMAND message. Some Windows messages include, WM_CREATE (invoked when the window is created), WM_LBUTTONDOWN (invoked when the user clicks the left mouse button), and WM_MOUSEMOVE (invoked when you move the mouse). The parameters of these messages decide the way the message has to be handled. The message handlers for Windows messages are predefined. For instance, OnMouseMove is the message handler for the WM_MOUSEMOVE message, and OnLButtonDown is the message handler for the WM_LBUTTONDOWN message.

Control notification messages. Messages generated as a result of a user’s interaction with various controls, such as a button of a dialog box, and other child windows. All WM_COMMAND notification messages are control notification messages. For instance, when the user edits the text in an edit control, a WM_COMMAND message, along with the notification code

EN_CHANGE, is generated. Routing of control notification messages is similar to the routing of Windows messages, except for the BN_CLICKED control notification message, which is routed like a command message.

34Part I INTRODUCING VC++.NET

Command messages. Messages generated as a result of a user’s interaction with user-interface components, such as menus and toolbars. These are the WM_COMMAND notification messages. For handling command messages, you need to create your own message handlers, which is unlike the Windows messages that have predefined message handlers.

USER-DEFINED MESSAGES

Besides the three categories of messages listed, you can also have user-defined messages. All messages are internally mapped to a #defined value. Hence, using the same logic, you can define your own message by assigning it a unique #defined value. Because the message is user-defined, the application has to explicitly generate the message. To do so, you can use the SendMessage function, which also accepts the ID of the message to be generated, or PostMessage functions.

As a part of the message map, MFC provides you with message map macros to map the messages with the appropriate message handlers and class in which the message will be handled. The following are the macros available:

DECLARE_MESSAGE_MAP.

You add this macro right at the end of the class declaration to specify that the concerned class is handling some messages. The message handlers are defined as member functions of this class. The syntax for this macro is as follows:

DECLARE_MESSAGE_MAP()

BEGIN_MESSAGE_MAP. You use this macro to indicate the beginning of the message map entries. This macro accepts two parameters, the derived class name and the base class name:

BEGIN_MESSAGE_MAP(MyWindow, CFrameWnd)

In the given snippet, MyWindow is the name of the derived class (which contains the message handlers), while CFrameWnd is the base class. Following the BEGIN_MESSAGE_MAP macro entry, you should have the macro entries for each of the messages to be handled.

NOTE

The significance of specifying the base class name along with the derived class name in the BEGIN_MESSAGE_MAP macro is to direct those messages not handled by the derived class to the base class.

BASICS OF VC++.NET PROGRAMMING

Chapter 2

 

35

 

 

 

 

 

END_MESSAGE_MAP. You use this macro to mark the end of the message map entries. The syntax for this macro is as follows:

END_MESSAGE_MAP()

ON_COMMAND. You use this macro to map the message handlers for all command messages, such as messages generated when the user chooses a menu option. For example, when the user chooses File, Save, you want to display a message. To do this, you have defined a message handler named Display. The message map entry corresponding to this will be the following:

ON_COMMAND(ID_SAVE, Display)

In the preceding code, the first parameter, ID_SAVE, is the ID of the menu option (which you define while designing the menu), and the second parameter, Display, is the message handler that will display the message.

CAUTION

Don’t place a semicolon at the end of DECLARE_MESSAGE_MAP(),

BEGIN_MESSAGE_MAP(), and other message map macros.

The following is a sample application that

 

 

 

MACRO FOR USER-DEFINED

illustrates the implementation of the

 

message maps. When you execute this

You use the ON_MESSAGE macro to map

application and press the left mouse but-

user-defined messages. Remember that

ton, a message will be displayed.

the user-defined message should have an

# include <afxwin.h>

ID different from the predefined values

used by any of the Windows messages.

 

 

To trap the last message ID assigned by

class MyWindow:public CFrameWnd

Windows, you can use WM_USER, which

{

 

stores the last ID assigned.

 

 

public:

 

 

MyWindow()

 

{

 

 

Create(NULL,”Example Window”);

MessageBox(“Created”);

36

Part I

INTRODUCING VC++.NET

 

 

 

NOTE

The Windows messages that have predefined message handlers also have predefined message map macros. For instance, the message map macro for the WM_CREATE message is ON_WM_CREATE(). This automatically invokes the corresponding OnCreate function without you specifying it in the macro.

}

void OnLButtonDown(UINT flag, CPoint point)

{

MessageBox(“Left Button Down”);

}

DECLARE_MESSAGE_MAP()

};

BEGIN_MESSAGE_MAP(MyWindow, CFrameWnd)

ON_WM_LBUTTONDOWN()

END_MESSAGE_MAP()

class MyApp:public CWinApp

{

public:

BOOL InitInstance()

{

MyWindow *MyWindowObject = new MyWindow; m_pMainWnd=MyWindowObject; MyWindowObject->ShowWindow(SW_SHOWNORMAL);

return TRUE;

}

};

MyApp app;

The required code in the preceding code snippet is highlighted in bold for easy identification. The remainder of this section quickly runs through the sample application.

BASICS OF VC++.NET PROGRAMMING

Chapter 2

 

37

 

 

 

 

 

The window class of the sample application has been designed to handle messages. Hence, the DECLARE_MESSAGE_MAP macro is placed at the end of the class declaration. After the declaration, the BEGIN_MESSAGE_MAP macro is placed. It accepts MyWindow, which is the name of the derived class, and CFrameWnd, which is the base class, as parameters indicating that MyWindow class will handle the messages. The ON_LBUTTON_DOWN() macro is used to trap the WM_LBUTTONDOWN message, which will be generated once the user clicks the left button. Corresponding to this message, OnLButtonDown is the message handler. To summarize the working of this application:

1.The user clicks the left mouse button, which results in the WM_LBUTTONDOWN message.

2.The Run member function of the CWinApp class retrieves the message and directs it to the window class.

3.Control passes to the MyWindow class because it has the message map entries.

4.The ON_LBUTTON_DOWN() macro is executed, which further invokes the

OnLbuttonDown message handler.

5.The MessageBox function within the OnLButtonDown message handler displays the given message.

To execute this application, you can edit the previous application that you created.

You now know how to handle messages in your application. You will learn more about message handling in the subsequent chapters. Moving ahead, the next section explains the second most predominant feature of Windows programming, device independence, and how MFC supports it.

Device Independence

In this world of graphical user interface (GUI) operating systems, support of graphics is one of the main features that any programming model should cater to. Of course, Windows, the first GUI operating system, is no exception. In fact, the use of graphics is one of the core components of Windows programming, because in Windows, every output, whether it is text, an image, or a picture, is “painted” to the screen as graphics. This is implemented using the Graphical Device Interface (GDI), which provides the basic functionalities of drawing. (GDI provides predefined set of GDI objects, such as pens and brushes, which enable you to render drawings on any device. You will learn more about GDI objects in one of the

38

Part I

INTRODUCING VC++.NET

 

 

 

subsequent sections.) GDI acts as the interface between the application and the actual output device, whether a screen or a printer, and thus insulates the application from writing to the output device directly.

The GDI takes care of rendering the output to the appropriate output device by interacting with the device drivers. Figure 2-9 depicts the difference between DOS programs handling devices and Windows programs handling devices.

Screen

DOS Application

Devices

 

 

Printer

Screen

Windows Application

 

 

GDI

 

Devices

 

 

 

 

 

 

 

 

 

Printer

FIGURE 2-9 Device handling in DOS and Windows

Am I getting closer to the concept of device independence? Yes, I’m almost there. The only other question is how does GDI take care of device independence? It does this by using device contexts.

Device Contexts

A device context is a data structure that is a logical representation of the physical devices, such as a VDU or a printer. A device context contains the drawing attributes, such as colors, and drawing tools (GDI objects), such as pens and brushes, of the device. Besides handling physical devices, a device context can also handle logical devices, such as metafiles. A metafile stores the pictures in a device-inde- pendent form, which you can use to store and reproduce pictures later. Metafiles are similar to the disk files used to store data.

MFC provides you with a set of classes to handle a device context. Figure 2-10 displays the hierarchy of MFC device context classes, which are described next:

BASICS OF VC++.NET PROGRAMMING

Chapter 2

 

39

 

 

 

 

 

CObject

CDC

CClient

CPaintDC

CWindowDC

CMetaFileDC

FIGURE 2-10 The MFC device context classes

CDC. The CDC class is the base class for all other device context classes. This class provides member functions to work with device contexts, such as a VDU or a printer, and to work with the client area of a window.

Besides the member functions for handling device contexts, the CDC class also provides member functions to handle GDI objects, functions for retrieving and setting drawing attributes, and functions for drawing. As with any other classes, to work with the CDC class, you first need to construct the object and then call the appropriate member functions to draw onto the device contexts.

CClientDC. The CClientDC class, which is one of the derived classes of CDC, is used to work with the client areas of a window. This class provides member functions that you can use to draw onto the client area of a window. The CClientDC class uses the GetDC function to construct a device context and uses the ReleaseDC function to release it.

CPaintDC. The CPaintDC class, derived from the CDC class, handles the processing of the WM_PAINT message. Recall the use of BeginPaint and EndPaint API functions to paint the window of an application. The