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

Beginning Visual C++ 2005 (2006) [eng]-1

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

Windows Programming with the Microsoft Foundation Classes

How the Program Works

As in the trivial MFC example you looked at earlier in this chapter, the application object is created at global scope in our SDI program. You can see this if you expand the Global Functions and Variables item in the Class View, and then double-click on theApp. In the Editor window you’ll see this statement:

CTextEditorApp theApp;

This declares the object theApp as an instance of our application class CTextEditorApp. The statement is in the file TextEditor.cpp, which also contains member function declarations for the application class, and the definition of the CAboutDlg class.

After the object theApp has been created, the MFC-supplied WinMain() function is called. This in turn calls two member functions of the theApp object. First it calls InitInstance(), which provides for any initialization of the application that is necessary, and then Run(), which provides initial handling for Windows messages. The WinMain() function does not appear explicitly in the project source code because it is supplied by the MFC class library and is called automatically when the application starts.

The InitInstance() Function

You can access the code for the InitInstance() function by double-clicking its entry in the Class View after highlighting the CTextEditorApp class — or if you’re in a hurry, you can just look at the code immediately following the line defining the theApp object. The version created by the MFC Application wizard is as follows:

BOOL CTextEditorApp::InitInstance()

{

//InitCommonControlsEx() is required on Windows XP if an application

//manifest specifies use of ComCtl32.dll version 6 or later to enable

//visual styles. Otherwise, any window creation will fail. INITCOMMONCONTROLSEX InitCtrls;

InitCtrls.dwSize = sizeof(InitCtrls);

//Set this to include all the common control classes you want to use

//in your application.

InitCtrls.dwICC = ICC_WIN95_CLASSES;

InitCommonControlsEx(&InitCtrls);

CWinApp::InitInstance();

//Initialize OLE libraries if (!AfxOleInit())

{

AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE;

}

AfxEnableControlContainer();

//Standard initialization

//If you are not using these features and wish to reduce the size

//of your final executable, you should remove from the following

//the specific initialization routines you do not need

//Change the registry key under which our settings are stored

669

Chapter 12

//TODO: You should modify this string to be something appropriate

//such as the name of your company or organization SetRegistryKey(_T(“Local AppWizard-Generated Applications”));

LoadStdProfileSettings(4); // Load standard INI file options (including MRU)

//Register the application’s document templates. Document templates

//serve as the connection between documents, frame windows and views CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CTextEditorDoc),

RUNTIME_CLASS(CMainFrame),

// main SDI frame window

RUNTIME_CLASS(CTextEditorView)); if (!pDocTemplate)

return FALSE; AddDocTemplate(pDocTemplate);

//Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

//Dispatch commands specified on the command line. Will return FALSE if

//app was launched with /RegServer, /Register, /Unregserver or /Unregister. if (!ProcessShellCommand(cmdInfo))

return FALSE;

//The one and only window has been initialized, so show and update it

m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow();

//call DragAcceptFiles only if there’s a suffix

//In an SDI app, this should occur after ProcessShellCommand return TRUE;

}

The bits of the code that I want to mention at this point are shaded. The string passed to the SetRegistryKey() function are used to define a registry key under which program information is stored. You can change this to whatever you want. If I changed the argument to “Horton”, information about our program would be stored under the registry key

HKEY_CURRENT_USER\Software\Horton\TextEditor\

All the application settings are stored under this key, including the list of files most recently used by the program. The call to the function LoadStdProfileSettings() loads the application settings that were saved last time around. Of course, the first time you run the program, there aren’t any.

A document template object is created dynamically within InitInstance() by the statement:

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

 

RUNTIME_CLASS(CTextEditorDoc),

 

RUNTIME_CLASS(CMainFrame),

// main SDI frame window

RUNTIME_CLASS(CTextEditorView));

670

Windows Programming with the Microsoft Foundation Classes

The first parameter to the CSingleDocTemplate constructor is a symbol, IDR_MAINFRAME, which defines the menu and toolbar to be used with the document type. The following three parameters define the document, main frame window, and View Class objects that are to be bound together within the document template. Because you have an SDI application here, there is only one of each in the program, managed through one document template object. RUNTIME_CLASS() is a macro that enables the type of a class object to be determined at run-time.

There’s a lot of other stuff here for setting up the application instance that you need not worry about. You can add any initialization of your own that you need for the application to the InitInstance() function.

The Run() Function

The Run() function in the CTextEditorApp class is inherited from the application base class CWinApp. Because the function is declared as virtual, you can replace the base class version of the function Run() with one of your own, but this is not usually necessary so you don’t need to worry about it.

Run() acquires all the messages from Windows destined for the application and ensures that each message is passed to the function in the program designated to service it, if one exists. Therefore, this function continues executing as long as the application is running. It terminates when you close the application.

Thus, you can boil the operation of the application down to four steps:

1.Creating an application object, theApp.

2.Executing WinMain(), which is supplied by MFC.

3.WinMain() calling InitInstance(), which creates the document template, the main frame window, the document, and the view.

4.WinMain() calling Run(), which executes the main message loop to acquire and dispatch Windows messages.

Creating an MDI Application

Now let’s create an MDI application using the MFC Application wizard. Give it the project name Sketcher — and plan on keeping it as you will be expanding it into a sketching program during subsequent chapters. You should have no trouble with this procedure because there are only three things that you need to do differently from the process that you have just gone through for the SDI application. You should leave the default option, MDI, rather than changing to the SDI option. Under the Document Template Strings set of options in the Application Wizard dialog box you should specify the file extension as ske. You should also leave the base class for the CSketcherView class as CView under the

Generated Classes set of options.

You can see in the dialog box with Generated Classes selected that you get an extra class for your application compared to the TextEditor example, as Figure 12-12 shows.

671

Chapter 12

Figure 12-12

The extra class is CChildFrame, which is derived from the MFC class CMDIChildWnd. This class provides a frame window for a view of the document that appears inside the application window created by a CMainFrame object. With an SDI application there is a single document with a single view, so the view is displayed in the client area of the main frame window. In an MDI application, you can have multiple documents open, and each document can have multiple views. To accomplish this, each view of a document in the program has its own child frame window created by an object of the class CChildFrame. As you saw earlier, a view is displayed in what is actually a separate window, but one which exactly fills the client area of a frame window.

Running the Program

You can build the program in exactly the same way as the previous example. Then, if you execute it, you get the application window shown in Figure 12-13.

In addition to the main application window, you have a separate document window with the caption Sketch1. Sketch1 is the default name for the initial document, and it has the extension .ske if you save it. You can create additional views for the document by selecting the Window > New Window menu option. You can also create a new document by selecting File > New, so that there will be two active documents in the application. The situation with two documents active, each with two views open, is shown in Figure 12-14.

You can’t yet actually create any data in the application because we haven’t added any code to do that, but all the code for creating documents and views has already been included by the Application wizard.

672

This is created as a CMainFrame instance
Two views of The menu and toolbar are created by the CMainFrame object but are shared document
Sketch2 These are created as CChildFrame instances
This is a window in the client area of the CChildFrame window.
It is created by a CSketcherView object and will display document data.

Windows Programming with the Microsoft Foundation Classes

Figure 12-13

Two views of document Sketch1

Figure 12-14

673

Chapter 12

Summar y

In this chapter, you’ve been concerned mainly with the mechanics of using the MFC Application wizard. You have seen the basic components of the MFC programs the Application wizard generates for both SDI and MDI applications. All our MFC examples are created by the MFC Application wizard, so it’s a good idea to keep the general structure and broad class relationships in mind. You probably won’t feel too comfortable with the detail at this point, but don’t worry about that now. You’ll find that it becomes much clearer after you begin developing applications in the succeeding chapters.

The key points covered in this chapter are:

The MFC Application wizard generates a complete, working, framework Windows application for you to customize to your requirements.

The Application wizard can generate single document interface (SDI) applications which work with a single document and a single view, or multiple document interface (MDI) programs which can handle multiple documents with multiple views simultaneously.

The four essential classes in an SDI application that are derived from the foundation classes are:

The application class

The frame window class

The document class

The view class

A program can have only one application object. This is defined automatically by the Application wizard at global scope.

A document class object stores application-specific data and a view class object displays the contents of a document object.

A document template class object is used to tie together a document, a view, and a window. For an SDI application, a CSingleDocTemplate class does this, and for an MDI application, the CDocTemplate class is used. These are both foundation classes and application-specific versions do not normally need to be derived.

Exercises

It isn’t possible to give programming examples for this chapter, because it really just introduced the basic mechanics of creating MFC applications. There aren’t solutions to all the exercises because you will either see the answer for yourself on the screen, or be able to check your answer back with the text.

674

Windows Programming with the Microsoft Foundation Classes

However, you can download the source code for the examples in the book and the solutions to other exercises from http://www.wrox.com.

1.What is the relationship between a document and a view?

2.What is the purpose of the document template in an MFC Windows program?

3.Why do you need to be careful, and plan your program structure in advance, when using the Application wizard?

4.Code up the simple text editor program. Build both debug and release versions, and examine the types and sizes of the files produced in each case.

5.Generate the text editor application several times, trying different window styles from the Advanced Options in Application wizard.

675

13

Working with Menus and Toolbars

In the last chapter, you saw how a simple framework application generated by the MFC Application Wizard is made up and how the parts interrelate. In this chapter, you’ll start customizing an MDI framework application called Sketcher with a view to making it into a useful program. The first step in this process is to understand how menus are defined in Visual C++ 2005, and how functions are created to service the application-specific menu items that you add to your program. You’ll also see how to add toolbar buttons to the application. By the end of this chapter, you’ll have learned about:

How an MFC-based program handles messages

Menu resources, and how you can create and modify them

Menu properties, and how you can create and modify them

How to create a function to service the message generated when a menu item is selected

How to add handlers to update menu properties

How to add toolbar buttons and associate them with existing menu items

Communicating with Windows

As you saw in Chapter 11, Windows communicates with your program by sending messages to it. Most of the drudgery of message handling is taken care of by MFC, so you don’t have to worry about providing a WndProc() function at all. MFC enables you to provide functions to handle the individual messages that you’re interested in and to ignore the rest. These functions are referred to as message handlers or just handlers. Because your application is MFC-based, a message handler is always a member function of one of your application’s classes.

The association between a particular message and the function in your program that is to service it is established by a message map — each class in your program that can handle Windows messages will have one. A message map for a class is simply a table of member functions that handle

Chapter 13

Windows messages. Each entry in the message map associates a function with a particular message; when a given message occurs, the corresponding function is called. Only the messages relevant to a class appear in the message map for the class.

A message map for a class is created automatically by the MFC Application wizard when you create a project or by ClassWizard when you add a class that handles messages to your program. Additions to, and deletions from, a message map are mainly managed by ClassWizard, but there are circumstances where you need to modify the message map manually. The start of a message map in your code is indicated by a BEGIN_MESSAGE_MAP() macro, and the end is marked by an END_MESSAGE_MAP() macro. Let’s look into how a message map operates using our Sketcher example.

Understanding Message Maps

A message map is established by the MFC Application wizard for each of the main classes in your program. In the instance of an MDI program such as Sketcher, a message map is defined for each of

CSketcherApp, CSketcherDoc, CSketcherView, CMainFrame, and CChildFrame. You can see the message map for a class in the .cpp file containing the implementation of the class. Of course, the functions that are included in the message map also need to be declared in the class definition, but they are identified here in a special way. Look at the definition for the CSketcherApp class shown here:

class CSketcherApp : public CWinApp

{

public:

CSketcherApp();

//Overrides public:

virtual BOOL InitInstance();

//Implementation

afx_msg void OnAppAbout(); DECLARE_MESSAGE_MAP()

};

Only one message handler, OnAppAbout(), is declared in the CSketcherApp class. The word afx_msg at the beginning of the line declaring the OnAppAbout() function is just to distinguish a message handler from other member functions in the class. It is converted to white space by the preprocessor, so it has no effect when the program is compiled.

The macro DECLARE_MESSAGE_MAP() indicates that the class can contain function members that are message handlers. In fact, any class that you derive from the MFC class CCmdTarget can potentially have message handlers, so such classes will have this macro included as part of the class definition by the MFC Application wizard or by the Add Class wizard that you’ll use to add a new class for a project, depending on which was responsible for creating it. Figure 13-1 shows the MFC classes derived from CCmdTarget that have been used in our examples so far.

The classes that have been used directly, or as a direct base for our own application classes, are shown shaded. Thus, the CSketcherApp class has CCmdTarget as an indirect base class and, therefore, are

678