1. Trang chủ
  2. » Công Nghệ Thông Tin

Ivor Horton’s Beginning Visual C++ 2005 phần 7 doc

122 291 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 122
Dung lượng 2,01 MB

Nội dung

A declaration has been added for each of the handlers that you’ve specified in the Event Handler wizard dialog box. Each of the function declarations has been prefixed with afx_msg to indicate that it is a mes- sage handler. The Event Handler wizard also automatically updates the message map in your CSketcherDoc class implementation with the new message handlers. If you take a look in the file SketcherDoc.cpp, you’ll see the message map as shown here: BEGIN_MESSAGE_MAP(CSketcherDoc, CDocument) ON_COMMAND(ID_COLOR_BLACK, OnColorBlack) ON_COMMAND(ID_COLOR_RED, OnColorRed) ON_COMMAND(ID_COLOR_GREEN, OnColorGreen) ON_COMMAND(ID_COLOR_BLUE, OnColorBlue) ON_COMMAND(ID_ELEMENT_LINE, OnElementLine) ON_COMMAND(ID_ELEMENT_RECTANGLE, OnElementRectangle) ON_COMMAND(ID_ELEMENT_CIRCLE, OnElementCircle) ON_COMMAND(ID_ELEMENT_CURVE, OnElementCurve) END_MESSAGE_MAP() The Event Handler wizard has added an ON_COMMAND() macro for each of the handlers that you have identified. This associates the handler name with the message ID, so, for example, the member function OnColorBlack() is called to service a COMMAND message for the menu item with the ID ID_COLOR_BLACK. Each of the handlers generated by the Event Handler wizard is just a skeleton. For example, take a look at the code provided for OnColorBlue(). This is also defined in the file SketcherDoc.cpp, so you can scroll down to find it, or go directly to it by switching to the Class View and double-clicking the function name after expanding the tree for the class CSketcherDoc (make sure that the file is saved first): void CSketcherDoc::OnColorBlue() { // TODO: Add your command handler code here } As you can see, the handler takes no arguments and returns nothing. It also does nothing at the moment, but this is hardly surprising, because the Event Handler wizard has no way of knowing what you want to do with these messages! Coding Menu Message Functions Now consider what you should do with the COMMAND messages for our new menu items. I said earlier that you want to record the current element and color in the document, so you need to add a data mem- ber to the CSketcherDoc class for each of these. Adding Members to Store Color and Element Mode You could add the data members that you need to the CSketcherDoc class definition just by editing the class definition directly, but let’s use the Add Member Variable wizard to do it. Display the dialog box for the wizard by right-clicking the CSketcherDoc class name in the Class View and then selecting Add > Add Variable from the pop-up menu that appears. You then see the dialog box for the wizard as shown in Figure 13-8. 692 Chapter 13 16_571974 ch13.qxp 1/20/06 11:26 PM Page 692 Figure 13-8 I’ve already entered the information in the dialog box for the m_Element variable that stores the current element type to be drawn. I have selected protected as the access because it should not be accessible directly from outside the class. I have also selected the type as unsigned int because you use a posi- tive integer to identify each type of element. When you click the Finish button, the variable is added to the class definition in the CSketcherDoc.h file. Add the CSketcherDoc class member to store the element color manually just to show that you can. Its name is m_Color and its type is COLORREF, which is a type defined by the Windows API for represent- ing a color as a 32-bit integer. You can add the declaration for the m_Color member to the CSketcherDoc class like this: class CSketcherDoc : public CDocument { // Generated message map functions protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnColorBlack(); afx_msg void OnColorRed(); afx_msg void OnColorGreen(); afx_msg void OnColorBlue(); afx_msg void OnElementLine(); afx_msg void OnElementRectangle(); afx_msg void OnElementCircle(); afx_msg void OnElementCurve(); protected: 693 Working with Menus and Toolbars 16_571974 ch13.qxp 1/20/06 11:26 PM Page 693 // Current element type unsigned int m_Element; COLORREF m_Color; // Current drawing color }; The m_Color member is also protected, as there’s no reason to allow public access. You can always add functions to access or change the values of protected or private class members with the advantage that you then have complete control over what values can be set. Initializing the New Class Data Members You need to decide how to represent an element type. You could just set m_Element to a unique numeric value, but this would introduce “magic numbers” into the program, the significance of which would be less than obvious to anyone else looking at the code. A better way would be to define a set of constants that you can use to set values for the member variable, m_Element. In this way, you can use a standard mnemonic to refer to a given type of element. You could define the element types with the following statements: // Element type definitions // Each type value must be unique const unsigned int LINE = 101U; const unsigned int RECTANGLE = 102U; const unsigned int CIRCLE = 103U; const unsigned int CURVE = 104U; The constants initializing the element types are arbitrary unsigned integers. You can choose different values, if you like, as long as they are all distinct. If you want to add further types in the future, it will obviously be very easy to add definitions here. For the color values, it would be a good idea if we used constant variables that are initialized with the val- ues that Windows uses to define the color in question. You could do this with the following lines of code: // Color values for drawing const COLORREF BLACK = RGB(0,0,0); const COLORREF RED = RGB(255,0,0); const COLORREF GREEN = RGB(0,255,0); const COLORREF BLUE = RGB(0,0,255); Each constant is initialized by RGB(), which is a standard macro defined in the Wingdi.h, header file that is included as part of Windows.h. The three arguments to the macro define the red, green, and blue components of the color value respectively. Each argument must be an integer between 0 and 255, where these limits correspond to no color component and the maximum color component. RGB(0,0,0) corre- sponds to black because there are no components of red, green, or blue. RGB(255,0,0) creates a color value with a maximum red component, and no green or blue contribution. You can create other colors by combining red, green, and blue components. You need somewhere to put these constants, so let’s create a new header file and call it OurConstants.h. You can create a new file by right-clicking the Header Files folder in the Solution Explorer tab and select- ing the Add > Add New Item menu option from the pop-up. Enter the header file name OurConstants in the dialog box that displays and then click the Open button. You’ll then be able to enter the constant definitions in the Editor window as shown here. 694 Chapter 13 16_571974 ch13.qxp 1/20/06 11:26 PM Page 694 //Definitions of constants #pragma once // Element type definitions // Each type value must be unique const unsigned int LINE = 101U; const unsigned int RECTANGLE = 102U; const unsigned int CIRCLE = 103U; const unsigned int CURVE = 104U; /////////////////////////////////// // Color values for drawing const COLORREF BLACK = RGB(0,0,0); const COLORREF RED = RGB(255,0,0); const COLORREF GREEN = RGB(0,255,0); const COLORREF BLUE = RGB(0,0,255); /////////////////////////////////// As you’ll recall, the pre-processor directive #pragma once is there to ensure that the definitions cannot be included more than once in a file. The statements in the header file are included into a source file only by an #include directive if it has hasn’t been included previously. After the header has been included in a file, the statements will not be included again. After saving the header file, you can add the following #include statement to the beginning of the file Sketcher.h: #include “OurConstants.h” Any .cpp file that has an #include directive for Sketcher.h has the constants available. You can verify that the new constants are now part of the project by expanding Global Functions and Variables in the Class View. You’ll see the names of the color and element types that have been added now appear along with the global variable theApp. Modifying the Class Constructor It’s important to make sure that the data members you have added to the CSketcherDoc class are ini- tialized appropriately when a document is created. You can add the code to do this to the class construc- tor as shown here: CSketcherDoc::CSketcherDoc() : m_Element(LINE), m_Color(BLACK) { // TODO: add one-time construction code here } The wizard already has arranged that the m_Element member will be initialized to 0 so change the ini- tial value to LINE. You then need to add the initializer for the m_Color member with BLACK as the value so that everything is consistent with the initial check marks that you specified for the menus. Now you’re ready to add the code for the handler functions that you created for the Element and Color menu items. You can do this from the Class View. Click the name of the first handler function, OnColorBlack(). You just need to add one line to the function, so the code for it becomes: 695 Working with Menus and Toolbars 16_571974 ch13.qxp 1/20/06 11:26 PM Page 695 void CSketcherDoc::OnColorBlack() { m_Color = BLACK; // Set the drawing color to black } The only job that the handler has to do is to set the appropriate color. In the interests of conciseness, the new line replaces the comment provided originally. You can go through and add one line to each of the Color menu handlers setting the appropriate color value. The element menu handlers are much the same. The handler for the Element > Line menu item is: void CSketcherDoc::OnElementLine() { m_Element = LINE; // Set element type as a line } With this model, it’s not too difficult to write the other handlers for the Element menu. That’s eight mes- sage handlers completed. You can now rebuild the example and see how it works. Running the Extended Example Assuming that there are no typos, the compiled and linked program should run without error. When you run the program, you should see the window shown in Figure 13-9. Figure 13-9 The new menus are in place on the menu bar, and you can see that the items you have added to the menu are all there, and you should see the Prompt message in the status bar that you provided in the properties box when the mouse cursor is over a menu item. You could also verify that Alt+C and Alt+l work as well. The things that don’t work are the check marks for the currently selected color and element, which remain firmly stuck to their initial defaults. Let’s look at how you can fix that. 696 Chapter 13 16_571974 ch13.qxp 1/20/06 11:26 PM Page 696 Adding Message Handlers to Update the User Interface To set the check mark correctly for the new menus, you need to add the second kind of message handler, UPDATE_COMMAND_UI (signifying update command user interface), for each of the new menu items. This sort of message handler is specifically aimed at updating the menu item properties before the item is displayed. Go back to viewing the Sketcher.rc file in the Editor window. Right-click the Black item in the Color menu and select Add Event Handler from the pop-up menu. You can then select UPDATE_COMMAND_UI as the message type and CSketcherDoc as the class as shown in Figure 13-10. Figure 13-10 The name for an update function has been generated[md] OnUpdateColorBlack(). Because this seems a reasonable name for the function you want, click the Add and Edit button and have the Event Handler wizard generate it. As well as generating the skeleton function definition in SketcherDoc.cpp, its declara- tion is added to the class definition. An entry for it is also made in the message map that looks like this: ON_UPDATE_COMMAND_UI(ID_COLOR_BLACK, OnUpdateColorBlack) This uses the ON_UPDATE_COMMAND_UI() macro that identifies the function you have just generated as the handler to deal with update messages corresponding to the ID shown. You could now enter the code for the new handler but I’ll let you add command update handlers for each of the menu items for both the Color and Element menus first. Coding a Command Update Handler You can access the code for the OnUpdateColorBlack() handler in the CSketcherDoc class by select- ing the function in Class View. This is the skeleton code for the function: 697 Working with Menus and Toolbars 16_571974 ch13.qxp 1/20/06 11:26 PM Page 697 void CSketcherDoc::OnUpdateColorBlack(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here } The argument passed to the handler is a pointer to an object of the CCmdUI class type. This is an MFC class that is only used with update handlers, but it applies to toolbar buttons as well as menu items. The pointer points to an object that identifies the item that originated the update message so you use this to operate on the item to update how it appears before it is displayed. The CCmdUI class has five member functions that act on user interface items. The operations that each of these provides is as follows: Method Description ContinueRouting() Passes the message on to the next priority handler. Enable() Enables or disables the relevant interface item. SetCheck() Sets a check mark for the relevant interface item. SetRadio() Sets a button in a radio group on or off. SetText() Sets the text for the relevant interface item. We’ll use the third function, SetCheck(), as that seems to do what we want. The function is declared in the CCmdUI class as: virtual void SetCheck(int nCheck = 1); This function sets a menu item as checked if you pass 1 as the argument and set it unchecked if you pass 0 as the argument. The parameter has a default value of 1, so if you just want to set a check mark for a menu item regardless, you can call this function without specifying an argument. In our case, you want to set a menu item as checked if it corresponds with the current color. You can, therefore, write the update handler for OnUpdateColorBlack() as: void CSketcherDoc::OnUpdateColorBlack(CCmdUI* pCmdUI) { // Set menu item Checked if the current color is black pCmdUI->SetCheck(m_Color==BLACK); } The statement you have added calls the SetCheck() function for the Color > Black menu item, and the argument expression m_Color==BLACK results in 1 if m_Color is BLACK, or 0 otherwise. The effect, therefore, is to check the menu item only if the current color stored in m_Color is BLACK, which is pre- cisely what you want. The update handlers for all the menu items in a menu are always called before the menu is displayed so you can code the other handlers in the same way to ensure that only the item corresponding to the cur- rent color (or the current element) is checked: 698 Chapter 13 16_571974 ch13.qxp 1/20/06 11:26 PM Page 698 void CSketcherDoc::OnUpdateColorBlue(CCmdUI* pCmdUI) { // Set menu item Checked if the current color is blue pCmdUI->SetCheck(m_Color==BLUE); } void CSketcherDoc::OnUpdateColorGreen(CCmdUI* pCmdUI) { // Set menu item Checked if the current color is green pCmdUI->SetCheck(m_Color==GREEN); } void CSketcherDoc::OnUpdateColorRed(CCmdUI* pCmdUI) { // Set menu item Checked if the current color is red pCmdUI->SetCheck(m_Color==RED); } A typical Element menu item update handler is coded as: void CSketcherDoc::OnUpdateElementLine(CCmdUI* pCmdUI) { // Set Checked if the current element is a circle pCmdUI->SetCheck(m_Element==LINE); } You can now code all the other update handlers in a similar manner: void CSketcherDoc::OnUpdateElementCurve(CCmdUI* pCmdUI) { // Set Checked if the current element is a curve pCmdUI->SetCheck(m_Element==CURVE); } void CSketcherDoc::OnUpdateElementCircle(CCmdUI *pCmdUI) { // Set Checked if the current element is a circle pCmdUI->SetCheck(m_Element==CIRCLE); } void CSketcherDoc::OnUpdateElementRectangle(CCmdUI* pCmdUI) { // Set Checked if the current element is a rectangle pCmdUI->SetCheck(m_Element==RECTANGLE); } After you get the idea, it’s easy, isn’t it? Exercising the Update Handlers When you’ve added the code for all the update handlers, you can build and execute the Sketcher appli- cation again. Now, when you change a color or an element type selection, this is reflected in the menu, as shown in Figure 13-11. 699 Working with Menus and Toolbars 16_571974 ch13.qxp 1/20/06 11:26 PM Page 699 Figure 13-11 You have completed all the code that you need for the menu items. Make sure that you have saved everything before embarking on the next stage. These days, toolbars are a must in any Windows pro- gram of consequence, so the next step is to take a look at how you can add toolbar buttons to support our new menus. Adding Toolbar Buttons Select the Resource View and extend the toolbar resource. You’ll see that it has the same ID as the main menu, IDR_MAINFRAME. If you double-click this ID, the Editor window appears as shown in Figure 13-12. Figure 13-12 700 Chapter 13 16_571974 ch13.qxp 1/20/06 11:26 PM Page 700 A toolbar button is a 16x15 array of pixels that contains a pictorial representation of the function it oper- ates. You can see in Figure 13-12 that the resource editor provides an enlarged view of a toolbar button so that you can see and manipulate individual pixels. If you click the new button at the right end of the row as indicated, you’ll be able to draw this button. Before starting the editing, drag the new button about half a button width to the right. It separates from its neighbor on the left to start a new block. You should keep the toolbar button blocks in the same sequence as the items on the menu bar, so you’ll create the element type selection buttons first. You’ll be using the following editing buttons provided by the resource editor that appear in the toolbar for the Visual C++ 2005 application window. ❑ Pencil for drawing individual pixels ❑ Eraser for erasing individual pixels ❑ Fill an area with the current color ❑ Zoom the view of the button ❑ Draw a rectangle ❑ Draw an ellipse ❑ Draw a curve If it is not already visible, you can display the window for selecting a color by right-clicking a toolbar button and selecting Show Colors Window from the pop-up. Make sure that the black color is selected and use the pencil tool to draw a diagonal line in the enlarged image of the new toolbar button. In fact, if you want it a bit bigger, you can use the Magnification Tool editing button to enlarge it up to eight times its actual size. If you make a mistake, you can change to the Erase Tool editing button, but you need to make sure that the color selected corresponds to the background color for the button you are editing. You can also erase individual pixels by clicking them using the right mouse button, but again you need to be sure that the background color is set correctly when you do this. To set the background color, just click the appropriate color using the right mouse button. After you’re happy with what you’ve drawn, the next step is to edit the toolbar button properties. Editing Toolbar Button Properties Double-click your new button in the toolbar to bring up its properties window, as shown in Figure 13-13. The properties box shows a default ID for the button, but you want to associate the button with the menu item Element > Line that we’ve already defined, so click ID and then click the down arrow to display alternative values. You can then select ID_ELEMENT_LINE from the drop-down box. If you click on Prompt you’ll find that this also causes the same prompt to appear in the status bar because the prompt is recorded along with the ID. You can close the Properties window to complete the button definition. You can now move on to designing the other three element buttons. You can use the rectangle editing button to draw a rectangle and the ellipse button to draw a circle. You can draw a curve using the pencil to set individual pixels, or use the curve button. You need to associate each button with the ID corre- sponding to the equivalent menu item that you defined earlier. 701 Working with Menus and Toolbars 16_571974 ch13.qxp 1/20/06 11:26 PM Page 701 [...]... put all the code to draw the document in this function, the Application wizard has included a declaration for the pointer pDoc and initialized it using the function GetDocument(), which returns the address of the document object related to the current view: CSketcherDoc* pDoc = GetDocument(); The GetDocument() function actually retrieves the pointer to the document from m_pDocument, an inherited data... CSketcherDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; pDC->Arc(50,50,150,150,100,50,150,100); // Draw the 1st (large) circle // Define the bounding rectangle for the 2nd (smaller) circle CRect* pRect = new CRect(250,50,300,100); CPoint Start( 275 ,100); // Arc start point CPoint End(250 ,75 ); // Arc end point pDC->Arc(pRect,Start, End); // Draw the second circle delete pRect; } 71 6 Drawing... to the document class in the application, CSketcherDoc This is so that the compiler has access to the members of the document class that you’ve defined; otherwise, the compiler is able to access only the members of the base class Thus, pDoc points to the document object in your application associated with the current view, and you will be using it to access the data that you’ve stored in the document... draw a series of connected lines by just calling the LineTo() function for each line Look at the following version of the OnDraw() function: 71 4 Drawing in a Window void CSketcherView::OnDraw(CDC* pDC) { CSketcherDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; pDC->MoveTo(50,50); pDC->LineTo(50,200); pDC->LineTo(150,200); pDC->LineTo(150,50); pDC->LineTo(50,50); // // // // // Set the... The OnDraw() Member Function The implementation of the OnDraw() member function that’s created by the MFC Application wizard looks like this: 71 1 Chapter 14 void CSketcherView::OnDraw(CDC* /*pDC*/) { CSketcherDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; // TODO: add draw code for native data here } A pointer to an object of the CDC class type is passed to the OnDraw() member of the... or by calling a function to set it For example, you could extend the OnDraw() function to set the current position as follows: void CSketcherView::OnDraw(CDC* pDC) { CSketcherDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; pDC->MoveTo(50, 50); // Set the current position as 50,50 } The shaded line calls the MoveTo() function for the CDC object pointed to by pDC This member function... the old pen You can see this in action if you amend the previous version of the OnDraw() function in the CSketcherView class to: void CSketcherView::OnDraw(CDC* pDC) { CSketcherDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(!pDoc) return; // Declare a pen object and initialize it as // a red solid pen drawing a line 2 pixels wide CPen aPen; aPen.CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); CPen* pOldPen... The Drawing Mechanism in Visual C++ MFC encapsulates the Windows interface to your screen and printer and relieves you of the need to worry about much of the detail involved in programming graphical output As you saw in the last chapter, the Application wizard-generated program already contains a class derived from the MFC class CView that’s specifically designed to display document data onscreen The... and you will be using it to access the data that you’ve stored in the document object when you want to draw it The following line: ASSERT_VALID(pDoc); just makes sure that the pointer pDoc contains a valid address and the if statement that follows ensures that pDoc is not null The name of the parameter pDC for the OnDraw() function stands for “pointer to Device Context.” The object of the CDC class pointed... Application wizard generated the class CSketcherView to display information from a document in the client area of a document window The class definition includes overrides for several virtual functions, but the one of particular interest in here is the function OnDraw() This is called whenever the client area of the document window needs to be redrawn It’s the function that’s called by the application . others are displayed in lowercase. 70 5 Working with Menus and Toolbars 16_ 571 974 ch13.qxp 1/20/06 11:26 PM Page 70 5 16_ 571 974 ch13.qxp 1/20/06 11:26 PM Page 70 6 14 Drawing in a Window In this. CSketcherDoc class by select- ing the function in Class View. This is the skeleton code for the function: 6 97 Working with Menus and Toolbars 16_ 571 974 ch13.qxp 1/20/06 11:26 PM Page 6 97 void CSketcherDoc::OnUpdateColorBlack(CCmdUI*. that was previously hidden is exposed by the user moving another window. 17_ 571 974 ch14.qxp 1/20/06 11:22 PM Page 70 7 Fortunately, you don’t need to worry about the details of such occurrences,

Ngày đăng: 13/08/2014, 18:20