The fifth chapter Windows Message Mapping Windows message map In Chapter 3, you saw how the MFC library application framework calls the view class's virtual OnDraw function. In the online help for the MFC library, where it documents the Cview class and its base class, CWnd , you'll see several hundred member functions. Functions whose names begin with on-such as OnKeyDown and OnLButtonUp-are member functions that the application framework calls in response to various Windows "events" such as keystrokes and mouse clicks. in the third chapter You see how the MFC library application framework calls the view class's virtual function ondraw. In the online help of the MFC, in the CView class and its base class CWnd, you will see hundreds of member functions. Each function They are all started with the word on the word, such as the onkeyDown, which is a different Windows "event", such as the application frame call response, such as the keyboard tap and mouse button event. Most of these functions That Are Called by the Application Framework are not virtual functions and thus require more programming steps. This chapter explains how to use the Microsoft Visual C . NET Class View's Properties window to set up the message map structure necessary for connecting the application framework to your functions' Code. So many functions are impossible to apply the framework to call the virtual function. This chapter will use Microsoft VC .
.NET Class View window to set the attribute mapping message structure connected to the frame to complete the application program your function code. This chapter includes sample applications of message map functions. The first two applications user an ordinary Cview class. The Ex05a example shows the interaction between User-Driven Events and The OnDraw Function. The EFFECTS OF DIFFERENT Windows Mapping MapPing Modes. First, the two applications use the ordinary cView class .Ex05a example display The user uses the interaction between the event driver and the onDRAW function. EX05B shows the Windows mapping mode of different effects. More often Than NOT, HOWEVER, You'll Want A Scrolling View. The Last Example, EX05C, Users CscrollView in Place of the cview base class. This allows the mfc library application framework to insert Scroll Bars and connect the to the view. Often, you also need a view of the slide bar. In the last example, in the EX05C, use CScrollView in the CView base class this is to allow the MFC library application framework can insert a bar to their views Getting User Input:. Message Map Functions the Ex03a application from Chapter 3 does not accept user input (other than the standard Microsoft Windows resizing and window close commands) The window Contains Menus and a Toolbar, But These is not "CO nnected "to the view code. I will not discuss the menus and the toolbar until Part III of this book because they depend on the frame class, but plenty of other Windows input sources will keep you busy until then. However, before you can Process Any Windows Event, Even A Mouse Click, You Must Learn How To Use The MFC Library Message Map System. Get user input:
The EX03A application of the message mapping function Chapter 3 is unacceptable to user-entered (different Microsoft Windows Adjustments Size and Windows Turn off) with other standards. The window includes the menu and toolbar, but there is no "connection" to the view code. Since the menu and toolbar rely on the framework class, you can't introduce them before the third part, but many other Windows entries will make you busy. However, you can handle any Windows events, each mouse single before strikes, you have to learn how to use the message map system MFC library. the message map When the user clicks the left mouse button in a view window, Windows sends a message-specifically, WM_LBUTTONDOWN-to that widow. If your program needs to take action in response to WM_LBUTTONDOWN, your view class must have a member function that looks like this: Void CmyView :: OnLButtonDown (UINT nFlags, Cpoint point) {// event processing code here} your class header file must also have the corresponding Prototype: AFX_MSG Void OnlButtondown (uint nflags, cpoint point);
The afx_msg notation is a "no-op" that alerts you that this is a prototype for message map function Next, your code file needs a message maps macro that connects your OnLButtonDown function to the application framework:. BEGIN_MEAAGE_MAP (CmyView, Cview) ON_WM_LBUTTONDOWN () // entry specifically for OnLButtonDown // other message map entries END_MESSAGE_MAP () Finally, your class header file needs this statement: DECLARE_MESSAGE_MAP () How do you know which function goes with which Windows message Chapter Appendix A (and the MFC library? online documentation) includes a table that lists all standard Windows message and corresponding member function prototypes. you can manually code the message-handling functions-indeed, you still have to do that for certain messages. But fortunately, the code wizards available from Class View's Properties Window Automate The Coding of Most Message Map Functions. Message Map When the user mouse button Click the View window, Windows will send a specific message - WM_LBUTTONDOWN-giving the window. If your program needs to respond to this message, your view Categories must have the following member functions: void cm Yview :: ONLBUTTONDOWN (UINT NFLAGS, CPOINT POINT) {// Event Processing Code Here} You must also have a corresponding prototype in your class header: AFX_MSG Void ONLBUTTONDOWN (UINT NFLAGS, CPOINT); this AFX_MSG symbol is "what Not doing "it reminds this prototype is a message mapping function. Next, your code file requires message mapping macro to connect to your online: begin_meaage_map (cmyview, cview) ON_WM_LButtondown () // entry specification for ONLBUTTONDOWN // Other Message Map Entries End_MESSAGE_MAP () Finally, your class's header file requires this statement: declare_message_map () Do you know those functions to use those Windows messages?
Schedule A (also MFC Online Document) The table listed in the table contains all standard Windows messages and corresponding member function prototypes. You can manually process these message functions, but you still need to confirm the message. Fortunately, you can using class view properties window code wizard automatically increase the number of message mapping function Saving the view's State:. class Data Members If your program accepts input, you'll want the user to get some visual feedback the view's OnDraw function draws an image. based on the view's current state, and user actions can alter that stat. In a full-blown MFC library application, the document object holds the state of the application, but you're not to that point yet. For now, we'll use two view class data members, m_rectEllipse and m_nColor the first is an object of class CRect, which holds the current bounding rectangle of an ellipse, and the second is an integer that holds the current ellipse color value save view state: class Data members If your program accepts input, you want some feedback information to users. View's onDraw function drawn on the status of the view current status and user activity. In a mature MFC application, the document object saves the application. The state of the program, but you can't point out. Temporarily, we use two view classes of data members, M_Rectellipse, and M_ncolor. The first is a CRECT object, which saves the ellipse of the current rectangular range, the second is a shaping, it The color value of the current ellipse is saved. Note by Convertion, MFC Library Nonstatic Class Data Member Names Begin W ITH M_. Note: Press convention, MFC library non-static class member names start with m_. We'll make a message-mapse color (The View's State) Between Gray and White. (The Toggle IS). activated by a click of the left mouse button.) the initial values of m_rectEllipse and m_nColor are set in the view's constructor, and the color is changed in the OnLButtonDown member function. we arrange message mapping function ellipse color (view state) Gray and white changes. (Changed by the left mouse button). M_Rectellipse and M_nColor will initialize the value in the view constructor, the color changes in the ONLBUTTONDOWN function. Note why not use? Because If you do, you'll be in Trouble if your application, encapsulating data in objects.
Because you do this, if your app has multiple views you will have trouble. In addition, most of the object-oriented programming is to compress data into the object. Initializing a view class data member the most efficient place to initialize a Class data member is in the constructor, as shown here: CmyView :: CmyView (): m_rectEllipse (0,0,200,200) {...} You can initialize m_nColor with the same syntax We're using a built-. In Type (Integer), SO The Generated Code Is The Same if you use an assocY. Initializing view class data member The most effective initialization class data member is in the constructor, as shown below: CMYVIEW: : Cmyview (): m_rectellipse (0,0,200,200) {...
} You can also initialize the m_ncolor variable with the same syntax. We use the built-in type (integer), if you use this statement in the constructor, the resulting code is the same. Invalid Rectangle theory the onlbuttondown function can Toggle Thae value of m_nColor all day, but if that's all it did, the OnDraw function would not get called (unless, for example, the user resized the view window). The OnLButtonDown function must call the InvalidateRect function (a member function that the view class inherits from CWnd). InvalidateRect triggers a Windows WM_PAINT message, which is mapped in the Cview class to call to the virtual OnDraw function. If necessary, OnDraw can access the "invalid rectangle" parameter that was passed to InvalidateRect. You can optimize painting in Windows in two ways. First, you must be aware that Windows updates only those pixels that are inside the invalid rectangle. Thus, the smaller you make the invalid rectangle (in the OnLButtonDown handler, for instance), the more quickly it can be Repainted. Second, It's a Waste of Time To Execute Drawing Instructions Outside The Invalid rectangle. Your OnDraw function can call the CDC member function GetClipBox to determine the invalid rectangle, and then it can avoid drawing objects outside it. Remember that OnDraw is being called not only in response to your InvalidateRect call but also when the user resizes or exposes THE WINDOW. Thus, ONDRAW Is Responsible for All Drawing in A Window, And It Has To Adapt to Whatever Invalid Rectangle It gets.
Invalid Area Theory ONLBUTTONDOWN function can change the value of m_ncolor all day, but if it does, the OnDRAW function will not be called (unless, for example, the user re-adjusts the view window) .onlButtondown function must call the InValidateRect function (this member function inherits from CWnd Class) .INValidateRectC Trigger Windows WM_PAINT messages, call virtual functions onDraw. If necessary, OnDraw can access the "invalid area" parameter through InvalIdate. You have two in Windows to improve the drawing speed. First Method, you must understand that Windows only updates the pixels in the invalid area. Therefore, you only construct a small invalid area (for example, in ONLBUTTONDOWN processing), it will re-painted the speed will soon. Second method, you To waste time to perform drawing instructions outside the invalid area. Your overdraw function can call getClipbox's getClipbox's getClipbox to determine the invalid area, and it can avoid drawing to other objects. Remember, OnDRAW is not just your invalidaterect When the user is re-drawing and reproducing the window, it will also respond. Thus, OnDraw is the root cause of all the windows, and it can be obtained in any invalid area. For Win32 Progrmmers The MFC Library Makes It Easy To attach your own state variables to a window through C class data members. In Win32 programming, the WNDCALSS members cbClsExtra and cbWndExtra are available for this purpose, but the code for using this mechanism is so complex that developers tend to use global variables instead. to Win32 programmers MFC can easily bind to your own status variable to the window via C class data. In Win32 programming, Wndcalss members' cbclsextra and cbWndextra are used for this purpose, but this mechanism code It is very complicated, so developers have tended to replace it with a shared variable. The Window's Clie nt Area A window has a rectangular client area that excludes the border, caption bar, menu bar, and any docking toolbars. The CWnd member function GetClientRect supplies you with the client-area dimensions. Normally, you're not allowed to draw outside the Client Area, And Most Mouse Message Are Received Only When the Cursor is in the client area.
Window Customer Area One window consists of a rectangular customer area, tab bar, menu bar, and any barbeller bar, and any barbarbar. CWND member function can give your customer area size. Usually, you can't draw customer area And when your cursor is in the customer area, only most mouse information. CRECT, CPOINT, AND CSIZE ARITIC THE CREC, CPOINT, AND CSIZIZE CLASS 40, And Size Structures, And Thus They Inherit public integer data members, as follows: CRect left, top, right, bottom Cpoint x, y Csize cx, cy If you look in the MFC Library Reference, you'll see that these three classes have a number of overloaded operators you can. , among other things, do the following: Add a Csize object to a Cpoint object Subtract a Csize object from a Cpoint object Subtract one Cpoint object from another, yielding a Cszie object Add a Cpoint or Csize object to a CRect object Subtract a Cpoint or csize object from a CRect object The CRect class has member functions that relate to the csize and Cpoint classes. For example, the TopLeft member function returns a Cpoint object, and the Size member function returns a csize object. from this, yo U can begin to see That a csize object is the "Difference Between Two Cpoint Object" and "you can" bias "a crect object by a cpoint object.
CRECT, CPOINT, and CSIZE CRECT, CPOINT, and CSIZE are from Windows Rect, Point, and Size structures, and they all inherit from public variable integer data, as shown below: CRECT LEFT, TOP, RIGHT, BOTTOM CPoint X, Y CSIZE CX, CY If you have seen the MFC library reference book, you will see that these three classes are overloaded operands. You can do the following: Do CSIZE objects and CPOINT Objects add CSIZIZE objects from the CPOINT object to minus a cpoint from another CPOINT object, and the CSIZE object will also be affected. Call the CPOINT object or the CSIZE object to add CPOINT objects or CSIZE from the CRECT object. The member function in the object CRECT class involves the CSIZE and CPOINT class. For example, the Topleft member function returns a CPOINT object, and the size function returns a CSIZE object. From this, you can start seeing the CSIZE object is "Different in two CPOINT objects the "and you can Cpoint object" preference "CRect objects Determining Whether a Point is Inside a Rectangle the CRect class has a member function, PtInRect, that tests a point to see whether is falls inside a rectangle. the second OnLButtonDown parameter, point , is an object of class Cpoint that represents the cursor location in the client area of the window If you want to know whether that point is inside the m_rectEllipse rectangle, you can use PtInRect in this way:. If (m_rectEllipse.PtInRect (point) ) {// point is inside rectangle} as you'll Soon See, HoWever, this Simple Logic Appli Es Only if You're Working In Device Coordinates (Which You Are At this Stage). Decide whether a point is in a rectangular CRECT class function, PtinRect, it is testing a point in a rectangle .onlButtondown second parameter Point, is the location of the cPoint object indicated by the cursor where the curst is located. If you want to know if a point is in the M_Rectellipse's rectangle, you can pass this method: if (m_rectellipse.ptinRect (Point)) {// POINT Is Inside Rectangle} is also as you can see, however, if your work is in the equipment coordinate, this is just a simple logical application (temporary) The create lpcRect Operator if You Read The MFC Library Reference Carefully, You'll notice that CWnd :: InvalidateRect takes an LPCRECT parameter (a pointer to a RECT structure), not a CRect parameter. A CRect parameter is allowed because the CRect class defines an overloaded operator, LPCRECT (), that returns the address of a CRect object , Which is equivalent to the address of a reference object.
Thus, the compiler converts CRect arguments to LPCRECT arguments when necessary You call functions as if they have CRect reference parameters The following view member functions code retrieves the client rectangle coordinates and stores them in rectClient:.. CRect rectClient; GetClientRect (rectClient); CRect LPCRect operator If you read the MFC reference book seriously, you will notice that CWnd :: InvalIDateRect Arrange a parameter of the LPCRect (a pointer to the CRECT structure), no CRECT parameter. CRect class defines the allowed CRECT parameter is lprect () Overload, the address it returns is the CRECT object, which is an address equal to the Rect object. Therefore, the compiler transfers the CRECT parameter to the LPCRect parameter when the compiler is required. You call the function is as if references the CRECT parameter. view member function code after retrieving customer-related coordinates of the rectangle is saved in rectClient in: CRect rectClient; GetClientRect (rectClient); Determining Whether a Point Is Inside an Ellipse the Ex05a code determines whether the mouse hit is inside the rectangle If you want. . to make a better test you can find out whether the hit is inside the ellipse to do this, you construct an object of class CRgn that corresponds to the ellipse and then use the PtInRegion function instead of PtInRect Here's the code:.. CRgn rgn Rgn.createellLipti cRgnIndirect (m_rectEllipse); If (rgn.PtInRegion (poing)) {// point is inside ellipse} Note that the CreateEllipticRgnIndirct function is another function that takes an LPCRECT parameter It builds a special region structure within Windows that represents an elliptical region inside. A WINDOW. THAT STRUCTURE IS TENTTACHED TO The C CRGN Object In Your Program (The Same Type of Structure CAN ALSO REPRESENT A POLYGON.) Determines if a point is in an example of an elliptical internal EX05A to determine if the mouse is clicked inside the rectangle. if You have to test. You can find whether you click in the ellipse. Do you do it, you construct a CRGN object that meets the elliptical CRGN and use the PtinRegion function instead of the PtinRect function. CRGN RGN; RGN.
CreateEllipticRgnIndirect (m_rectEllipse); If (rgn.PtInRegion (poing)) {// point is inside ellipse} Note that a further arranged to have a function CreateEllipticRgnIndirct LPCRECT configuration parameters that a particular configuration in a Windows and described in the window. Elliptical area. This structure is attached to the C CRGN object in your program. (The same structure can also depict a polygon.) THE EX05A EXAMPLE IN THE EX05A EXAMPLE, AN Ellipse (Which happens to be a circle) changes color when the user clicks the left mouse button while the mouse cursor is inside the rectangle that bounds the ellipse. you'll use the view class data members to hold the view's state, and you'll use the InvalidateRect function to cause the view to be redrawn. in the Chapter 3 example, drawing in the window depends on only one function, OnDraw. The Ex05a example requires three customized functions (including the constructor) and two data members. The complete Cex05aView header and source code files are shown below ............................................................................................................................................................................................................................................................................ ~ 05A Example In an example of EX05A, when the user's mouse cursor is moved from the rectangle to the ellipse, click the ellipse with the left mouse button (the round is also elliptical) will change the color. You will use the view class data member to master the view status, and you will use The InvalIDateRect function triggers view redraw. In the third chapter, the drawing window rely on one function onDraw. EX05A requires three custom functions (including constructors) and two member functions. In the complete CEX05AVIEW header file And the source code file is displayed (these steps are listed after the code is created.) In the original MFC application wizard input and the black body code representation changed code in ONLBUTTONDOWN. // Code omitted USING CLASS View with EX05A look at the following Ex05aView.h source code: afx_msg void OnLButtonDown (UINT nFlags, Cpoint point); Now look at the following Ex05aView.cpp source code: ON_LBUTTONDOWN () The MFC Application Wizard used to generate comment lines for the benefit of the Class Wizard. Fortunately, The Comments Are no longer needed.
Visual C . NET Keeps track of the entire state of your code at all times, including mapping functions and maps to specific lines in your code. The code wizards available from the Class View's Properties window add message handler prototypes based on this internal information. In addition, the code wizards generate a skeleton OnLButtonDown member function in Ex05aView.cpp, complete with the correct parameter declarations and return type. Notice how the combination of the MFC Application Wizard and code wizards is different from a conventional code generator. You run a conventional code generator only once and then edit the resulting code. you run the MFC Application Wizard to generate the application only once, but you can run the code wizards as many as necessary, and you can edit the code at any time. use Ex05a in times Class view considers the source code of EX05AView.h: AFX_MSG Void ONLBUTTONDOWN (uint nflags, cpoing point); Now consider the source code for the following EX05AVIEW.CPP: ON_WM_LBUTTONDOWN () MFC Application Wizard's code wizard code generally generates a beneficial notes. Fortunately, these comments are not needed .vc . NE T is tracking all of your code, including mapping functions and maps in your code. The code wizard can add message handle based on internal information. In addition, the code wizard is still ONLBUTTONDOWN in EX05AVIEW.CPP. The framework of the member function, along with the correct parameter definition and return type. Note that the combination of the MFC Application Wizard and Code Wizard is a traditional code generator. You can only run a traditional code generator to edit the final Code. You run an MFC Application Wizard to generate an application, but you have to run many code wizards and you can edit your code at any time. Using the mfc Application Wizard and the code wizard together the following step wizard together the Following Steps show! MFC Application Wizard and the code wizards available from class View's Properties window to create this application: 1. Run the MFC Application Wizard to create Ex05a Use the wizard to generate an SDI project named Ex05a in the / vcppnet subdirectory The default class names are.. SHOWN Here.
... 2. Add the m_rectEllipse and m_nColor date members to Cex05aView Choose Class View from the View menu in Visual C NET and right-click the Cex05aView class Choose Add Variable and then insert the following two data members: private: CRect m_rectEllipse; Int m_nColor; If you prefer, you can type the above code inside the class declaration in the file ex05aView.h 3. Use the class View's Properties window to add a Cex05aView class message handler Select the Cex05aView class within class View, as shown in.. the following illustration. Next, right-click on Cex05aView and choose Properties. Click the Message button on the Properties window's toolbar. Scroll down and click on the WM_LBUTTONDOWN entry. You'll see a drop-down combo box appear next to the entry. SelectonLButtondown. The ONLBUTTONDOWN FUNCTION WILL BE WRITTEN INTO The Code and Will Appser Inside The Code Editor. Using the MFC App Wizard and Code Wizard The following steps Show you how to use the MFC App Wizard and Class Wizard with Class View Properties Window To create this app: 1. Run the MFC Application Wizard to establish an EX05A. Use the Wizard to generate a named EX in / vcppnet subdirectory 05A's SDI project. The default class name is shown below. 2. Add M_RECTELLIPE and M_NCOLOR data members to CEX05aview. Select Class View from the View menu of VC . Net and right-click Cex05aview class. Select to add variables and insert The following two data members: private: CRECT M_RECTELLIPSE; INT M_NCOLOR; if you are happy, you can insert the above code into the class definition of the EX05AView.h file. 3. Add CEX05AVIEW message handle using the class view property window. In the class view Select the CEX05aview class as shown below. Next, right-click CEX05AVIEW and select Properties. Click the message button on the Properties window toolbar. Scroll down and click the WM_LButtondown entry point. Select
OnLButtonDown. OnLButtonDown code and function will be written out to be published in the code editor. 4. Edit the OnLButtonDown code in Ex05aView.cpp.Once you add the message handler, the file Ex05aView.cpp will open in the Code Editor and the cursor will be positioned to the newly generated OnLButtonDown member function The following boldface code (that you type in) replaces the previous code:. Void Cex05aView :: OnLButtonDown (UINT nFlags, Cpoint point) {if (m_rectEllipse.PtInRect (point)) { if (m_nColor == GRAY_BRUSH) {m_nColor = WHITE_BRUSH;} else {m_nColor = GRAY_BRUSH;} InvalidateRct (m_rectEllipse);}} 5. Edit the constructor and the OnDraw function in Ex05aView.cpp The following boldface code (that you type in. ) replaces the previous code: Cex05aView :: Cex05aView ():... m_rectEllipse (0,0,200,200) {m_nColor = GRAY_BRUSH;} void Cex05aView :: OnDraw (CDC * pDC) {pDC-> SelectStockObject (m_nColor); pDC-> Ellipse (m_rectellipse);} 6. Build and Run The EX05A Program. Choose Build from The Build Menu or, On The Build Toolbar, Click The Button Show n here. Next, choose Start Without Debugging from the Debug menu. The resulting program will respond to clicks of the left mouse button by changing the color of the circle in the view widow. (Do not click the mouse's left button quickly in succession Windows Will Interpret this as a double-click Rather Than Two Single Click Rather Than Two Single ClickS.) 4. Edited the ONLBUTTONDOWN code in the EX05AVIEW.CPP file. You add a message handle, and EX05AVIEW.CPP will open the code editor and position the cursor to In the latest ONLBUTTONDOWN member function. Use the following black body code (you can also manually entertained) Replace the previous code: Void CEX05AVIEW :: ONLBUTTONDOWN (UINT NFLAGS, CPOINT) {if (m_rectellipse.ptinRect (Point) {IF (m_ncolor == gray_brush) {m_ncolor = white_brush;} else {m_ncolor = gray_brush;} invalidaterct (m_rectellipse);
}}} 5. Editing the constructor and the onDraw function of EX05AVIEW.CPP. Use the following black body code (you can also manually entered) replace the previous code: CEX05AView :: CEX05AView (): m_rectellipse (0,0,200,200) {m_ncolor = Gray_brush ;}.. Void CEX05AVIEW:: OONDRAW (CDC * PDC) {PDC-> SelectStockObject (m_ncolor); PDC-> Ellipse;} 6. Generate and run the EX05A program. Select Generate from the Generative menu, or single Take the generated button on the toolbar as follows: The diagram is slightly connected, select the start execution (not debug) in the debug menu. The circle of the result program will change the color through the left mouse button. (Do not continuous Click on the mouse quickly, compared with the two clicks, Windows will think this is double click. unique function, known as a window procedure, to each class. each time the application calls CreateWindow to create a window, it specifies a window class as parameter and thus links the newly created window to a window procedure function. This function, which is called Each Time Windows Sends a Message To The Window, Tests The Message Code That Passed As A Parameter and The Executes The Appropriate Code To Handle The Message. The MFC Application Framewo rk has a single window class and window procedure function for most window types. This window procedure function looks up the window handle (passed as a parameter) in the MFC handle map to get the corresponding C window object pointer. The window procedure function then uses the MFC runtime class system to determine the C class of the window object. Next, it locates the handler function in static tables created by the dispatch map functions, and finally it calls the handler function with the correct window object selected. to Win32 program A traditional Windows-based application registers a range of window classes (not the same in the C class), in this process,
Assign the unique function, you know the Window Procedure to each class, each application calls the CREATEWINDOW creation window, which specifies the window class as a parameter and connects to the newly established window to the window process function. This function, each When you are called by the Windows, you will send a message to the window. The test passed the message as a parameter and executes the appropriate code to process the message. The MFC application framework has a simple window class and a window function that handles many window types. This Window Process Functions are seen in the MFC handle map (as parameter delivery), is a pointer to the C window object. This window process function can determine the C class when using the MFC runtime system. Window object. Next, it is positioned to the handle function by assigning the mapping function in a static table, and finally it is determined by the currently selected window object. Using Windows Mapping Modes Up to now, Your Drawing units have been display pixels, also know as device coordinates. The Ex05a drawing units are pixels because the device context has the default mapping mode, MM_TEXT, assigned to it. The following statement draws a square of 200 by 200 pixels, with its top left corner at the top left of the window's client area (Positive y values increase as you move down the window.) pDC-> Rectangle (CRect (0,0,200,200));. This square will look smaller on a high-resolution display of 1024 -BY-768 Pixels Than On A Standard VGA Display That IS 640-by-480 Pixels, And It Will Look Tiny IF Printed On A Laser Printer with 600-DPI Resol Ution. (TRY EX05A's Print Preview Feature To See for Yourself.) Using Windows Mapping Mode to now, the plot unit you use is the pixel of the display, and you also know that the device coordinate. EX05A's drawing unit is a pixel because it is a device The context is indeed mapping mode, assigns MM_Text to it. Draw a 200x200 pixel square in the next declaration, the upper left corner of the window customer area. (With the increase of Y value you can move down the window .) PDC-> Rectangle (CRECT (0,0,200,200));
This square is small on the high resolution of 1024x768 pixels, which looks small on the standard VGA's 640x480 pixels, and if it looks very small if it is printed on a 600DPI resolution laser printer. (You try to print a preview of Ex05a function.) What if you want the square to be 4-by-4 centimeters (cm), regardless of the display device? Windows provides a number of other mapping modes, or coordinate systems, that you can associate with the device context. Coordinates in the current mapping mode are called logical coordinates. If you assign the MM_HIMETRIC mapping mode, for example, a logical unit is 1/100 millimeter (mm) instead of 1 pixel. in the MM_HIMETRIC mapping mode, the y axis runs in the opposite Direction to this in the mm_text mode: y values decreage as you move down. thus, a 4-by-4-cm Square is Drawn in Logical Coordinates this Way: PDC-> Rectangle ((CRECT (0,0,4000, - 4000));?. Looks easy, does not it Well, it is not, because you can not work only in logical coordinates Your program is always switching between device coordinates and logical coordinates, and you need to know when to convert Between them. this section Few Rules That Can make your programming life Easier. First, you need to know what mapping modes windows gives you. What if you want a square 4X4 cm square, regardless of the display device? Windows provides many other mapping patterns, Or the coordinate system, you can join the device context. Coordinates are called "logical coordinates" in the current mapping mode. If you assign mm_himetric mapping mode, for example, a logical unit is 1/100 mm instead of 1 pixel. In MM_HIMETRIC mapping mode, Y The axis runs in the opposite direction in mm_text mode: As the Y value reduces the same, you are moving down. So, the method of drawing 4x4 cm square logic coordinates is as follows: PDC-> Rectangle ((CRECT (0, 0, 0, 4000, -4000));
It looks easy, but it's not? Ok, it's not, because you can't work only in logical coordinates. Your program has been converted in the device coordinates and logical coordinates, and you need to know when they conversion. This Section gives you a rule to make you more easily plan your program. First, you need to know what WINDOWS will give you something map mode. The mm_text mapping mode at first Glance, mm_text Appears to be no mapping mode at all, But Rather Another name for device coordinates. Almost. In MM_TEXT, coordinates map to pixels, values of x increase as you move right, and values of y increase as you move down, but you're allowed to change the origin through calls to the CDC functions SetViewportOrg and SetWindowOrg. Here's some code that sets the window origin to (100,100) in logical coordinate space and then draws a 200-by-200-pixel square offset by (100,100). (An illustration of the output is shown in Figure 5-1 .) The Logical Point (100, 100) Maps to the Device Point (0). A Scrolling Window Uses this Kind of Transformation. Void CMYVIEW :: Ondraw (CDC * PDC) {PDC-> setmapmode (mm_text); PDC-> Setwindoworg (CPOINT (100, 100, 300, 300));} mm_text mapping mode first, MM_Text is not mapping mode, to another name - device coordinates. Almost. In m In m_text, the coordinates are mapped to pixels, and the X value increases. You will move right, the y value increases you will move, but you have to allow the origin by calling the CDC function setViewPortory and SetWindoworg. Some source code is set in logical coordinate space settings Window origin to (100, 100) and draw a square of 200x200 pixels of a position (100, 100) offset point. (This output is displayed in Figure 5-1.) This logical point (100, 100) is mapped to device points (0, 0). Use this conversion to scroll one window. Void CMYVIEW :: OnDRAW (CDC * PDC) {PDC-> setmapmode (mm_text); PDC-> SetWindoworg (CPOINT (100, 100)); PDC-> Rectangle (CRECT (100, 100, 300, 300)) ;
} The Fixed-Scale Mapping Modes One important group of Windows mapping modes provides fixed scaling. You've already seen that, in the MM_HIMETRIC mapping mode, x values increase as you move right and y values decrease as you move down. All fixed mapping Modes Follow this convention, and you can't change the fixed maping model, as shown in table 5-1. Table 5-1. The scale factor for mapping modes ---- -------------------------------------------------- -------------------- Mapping Mode Logical Unit ------------------------- -------------------------------------------------- MM_LOENGLISH 0.01 inch MM_HIENGLISH 0.001 inch MM_LOMETRIC 0.1 mm MM_HIMETRIC 0.01 mm MM_TWIPS 1/1440 inch The last mapping mode, MM_TWIPS, is most often used with printers. One twip is 1/20 point. (A point is a type measurement unit that equals exactly 1/72 inch in windows.) IF The mapping mode is mm_twips and you want, for example, 12-point type, you set the cha RACTER Height to 12x20 or 240, twips. The fixed scale of the fixed scale is an important part. You have seen it, the MM_HIMETRIC mapping mode, the X value increases right, y value Decrease down. All fixed mapping patterns follow this protocol and you can't change it. This is only different in the actual proportional factor of fixed scale mapping mode. Table 5-1 shown in Table 5-1 Table 5-1 Proportional factor in mapping mode ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------- Mapping mode logical unit --------------- -------------------------------------------------- ---------- MM_LOENGLISH 0.01 inch mm_hienglish 0.001 inch mm_lometric 0.1 cm mm_himetric 0.01 cm MM_TWIPS 1/1440 inch last mapping mode, MM_TWIPS, often on the printer. One ole is 1/12 points. It is the medium measurement unit to 1/72 inches in Windows.) If the mapping mode you want is MM_TWIPS, a 12-point type, you want to set the height of 12x20, or 240 缇. The variable-scale Mapping Modes Windows Provides Two Mapping Modes, MM_ISOTROPIC AND MM_ANISOTROPIC, That allow you to change the scale factory as well as the origin.
With these mapping modes, your drawing can change size as the user changes the size of the window. Also, if you invert the scale of one axis, you can "flip" an image about the other axis and you can define your own arbitrary fixed . -scale factors With the MM_ISOTROPIC mode, a 1: 1 aspect ration is always preserved In other words, a circle is always a circle as the scale factor changes With the MM_ANISOTROPIC mode, the x and y scale factors can change independently... . circles can be squished into ellipses Here's an OnDraw function that draws an ellipse that fits exactly in its window: Void CmyView :: OnDraw (CDC * pDC) {CRect rectClient; GetClientRect (rectClient); PDC-> SetMapMode (MM_ANISOTROPIC); PDC -> setWindowext (1000, 1000); PDC-> setViewPortext (RectClient.right, -RectClient.bottom); PDC-> SetViewportorg (RectClient.right / 2, RectClient.bottom / 2); PDC-> Ellipse (CRECT) 500, -500, 500, 500);} The variable proportion of mapping mode Windows provides two mapping patterns, mm_isotropic, and mm_anisotropic. It allows you to change the proportional factor and origin. When the user changes the window, you can change the size. Similarly, If you turn a shaft, you can Take the image of another ax of "reverse" and you can define yourself with any fixed scale factor. Use mm_isotropic mode, always maintain 1: 1 ratio configuration. In other words, a circle is always a circle. Using mm_anisotropic mode, the ratio relationship of x and y can be independent. The circle can be deformed into an ellipse. Draw a correct oval in the onDraw function: Void CMYVIEW :: OnDRAW (CDC * PDC) {CRECTCLIENT; getClientRect (rectClient); PDC-> SetMapMode (MM_ANISOTROPIC); PDC-> SetWindowExt (1000,1000); PDC-> SetViewportExt (rectClient.right, -rectClient.bottom); Pdc-> SetViewportOrg (rectClient.right / 2, rectClient. bottom / 2); Pdc-> Ellipse (CRECT (-500, -500,500,500));?} What's going on here The function SetWindowExt and SetViewportExt work together to set the scale, based on the window's current client rectangle returned by the GetClientRect function . The resulting window size is exactly 1000-by-1000 logical units.
. The SetViewportOrg function sets the origin to the center of the window Thus, a centered ellipse with a radius of 500 logical units fills the window exactly, as illustrated in Figure 5-2 Here are the formulas for converting logical units to device units.: X scale factor = x viewport extent / x window extent Y scale factor = y viewport extent / y window extent Device x = logical x X x scale factor x origin offset Device y = logical y X y scale factor y origin offset Suppose the window is 448 pixels wide (rectClient.right). The right edge of the ellipse's client rectangle is 500 logical units from the origin. The x scale factor is 448/1000, and the x origin offset is 448/2 device units. If you use the formulas shown above, the right edge of the ellipse's client rectangle comes out to 448 device units, the right edge of the window. The x scale factor is expressed as a ration (viewport extent / window extent) because Windows device coordinates are integers , NOT FLOATING-POINT VALUES. The EXTENT V alues are meaningless by themselves. If you substitute MM_ISOTROPIC for MM_ANISOTROPIC in the preceding example, the "ellipse" is always a circle, as shown in Figure 5-3. It expands to fit the smallest dimension of the window rectangle.
What else here? The setWindowext and the setViewPortext function are setting the proportion, which is based on the current window, which is returned by the getClientRect function. The result is that the window size is an accurate 1000x1000 logical unit .SetViewportorg function setting origin At the center of the window. Thus, a wound ellipse is accurately added to the radius of 500 logic units, as shown in Figure 5-2: Through these formulas can convert logical units to device unit: x ratio = viewport X Shaft area / window X-axis region Y ratio = viewport y-axis area / window Y-axis area device X = logic X multiplied by X ratio plus an offset device Y = logic y multiply by a y ratio plus Y origin Offset hypothesis window width is 448 pixels. The correct edge of its ellipse customer area 500 logical units from the origin. X ratio is 448/1000, and X origin offset is 448/2 device units. If You use the formula to display the above questions, the elliptical customer area comes out of 448 device units is the correct edge is also the correct edge of the window. Because the Windows device coordinates are integers, rather than floating point numbers, so X ratio is represented as a quantity (depending on Port extension / window stretch extension). This extension area is meaningless to them. If you use mm_isotropic instead of m_anisotropic in the previous example, this' ellipse will always be a circle, as shown in Figure 5-3 , expanding it in the region of the window size to fit a circle. Coordinate Conversion Once you set the mapping mode (plus the origin) of a device context, you can use logical coordinate parameters for most CDC member functions. If you get the mouse cursor coordinates from a Windows mouse message (the point parameter in OnLButtonDown), for example, you're dealing with device coordinates. Many other MFC library functions, particularly the member functions of class CRect, work correctly only with DEVICE COORDINATES. Note The CRECT ARITHMETIC FUNCT Arithmetic Functions, Which Assume That Right Is Greater Than LEFT AND BOTTOGER THAN TOP.
A rectangle (0,0,1000, -1000) in MM_HIMETRIC coordinates, for example, has bottom less than top and can not be processed by functions such as CRect :: PtlnRect unless your program first calls CRect :: NormalizeRect, which changes the rectangle's Data Members to (0, -1000, 1000, 0). Coordinate Conversion Once you set the mapping mode of the device context (plus origin), you can use the logical coordinate parameters to give a lot of CDC member functions. If you want to be from Windows The mouse cursor coordinate (ONLBUTTONDOWN POINT parameters), for example, the device coordinates you are processing. Many other MFC functions, typical, such as CRECT class member functions, only suitable for work in device coordinates. Note CRECT arithmetic functions Using the Rect arithmetic function below Win32, assume that the right side is larger than the top. A rectangle (0, 0, 1000, -1000) in the mm_himetric coordinate, for example, there is a bottom less than top, and cannot be functioned Processing, for example, CRECT:: PTLNRECT unless you first call CRECT :: NormalizeRect, which changes this rectangular data member is (0, -1000, 1000, 0). Furthermore, You're Likey to NEED A THIRD Set of Coordinates that we'll call physical coordinates. Why do you need another set? Suppose you're using the MM_LOENGLISH mapping mode in which a logical unit is 0.01 inch, but an inch on the screen represents a foot (12 inches) in the real world NOW Suppose The User Works in inches and decimal fractions. A measurement of 26.75 inches TRAN slates to 223 logical units, which must ultimately be translated to device point numbers or scaled long integers to avoid rounding-off errors. For the physical-to-logical translation, you're on your own, but the Windows GDI takes care of the logical-to-device translation for you. The CDC functions LptoDP and DptoLP translate between the two systems as long as the device context mapping mode and associated parameters have already been set. Your job is to decide when to use each system. Here are a few rules of thumb: ■ Assume that the CDC member functions take logical coordinate parameters ■ Assume that the Cwind member functions take device coordinate parameters ■ Do all hit-test operations in device coordinates...
Define regions in device coordinates. Functions such as Crect :: PtInRect work best with device coordinates. ■ Store long-term values in logical or physical coordinates. If you store a point in device coordinates and the user scrolls through a window, that point is No longer Valid. However, you may need a third coordinate system, we call the physical coordinates. Why do you need additional settings? Suppose you use mm_loenglish mapping mode in a logical unit 0.01 inches, but in the real world one inch on the screen The performance is one foot. Now suppose the user uses inch and has a decimal. To measure 26.75 inches to 223 logical units, the last must be converted to the number of device points or the long intensity to avoid rounding errors. From physics to logic Conversion, you want yourself, but Windows GDI is the conversion of logic to the device. The LPTODP and DPTOLP can be converted between the two systems when the device context mapping mode and associated parameters have been set. Your Work is to make judgments when using each system. Some experience methods: ■ CDC member function Receive logic coordinate parameters ■ CWind member function Receive device coordinate parameters ■ Do all collision test operations in the device coordinates. Define the area in device coordinates For the best way to work, CRECT:: PtinRect is the use of device coordinates ■ Save long-term values in logical or physical coordinates. If you store a point in the device coordinates and scroll through the window, then the point will not be long-term effective Suppose you need to know whether the mouse cursor is inside a rectangle when the user clicks the left mouse button the code is shown here:. // m_rect is CRect data member of the derived view class with MM_LOENGLISH // logical coordinates Void CMYVIEW :: ONLBUTTONDOWN (uint nfla GS, CPOINT POINT) {CRECT RECT = m_Rect; // Rect Is A Temporary Copy Of M_Rect. Cclientdc DC (this); // this is how we get a deice context // for setmapmode and lptodp // - more in next Chapter DC.SETMAPMODE (mm_loenglish); dc.lptodp (rect); // Rect is now in Device Coordinates if (Rect.ptinRect (Point)) {trace ("Mouse Cursor is Inside Rectangle./N");}} NOTIN CHAPTER 2). Note As You'll Soon See, It's Better To Set The Mapping Mode In The Virtual CView Function Onpreparedc Instead of in The OnDraw function.
If you need to know if the user clicks on the left mouse button button. Its code is as follows: // m_rect is the CRECT member function of the source self-view class using mm_loenglish logic coordinate void CMYVIEW :: ONLBUTTONDOWN (uint nflags CPOINT POINT) {create Rect = m_Rect; // RECT temporarily copy to m_rect. Cclientdc dc (this); // How do we get device context // From setmapmode to lptodp // - More in the next chapter Dc.SetmapMode (Mm_loenglish); dc.lptodp (rect); // Rect is now in device coordinates if (Rect.pt (Point)) {trace ("Mouse Cursor is Inside Rectangle./N");}} Trace Macro (hidden in Chapter 2). Note. When you will soon see, it can set mapping mode in virtual cView function onpreparedc and replacing the onDraw function. The EX05B EXAMPLE: Converting to the mm_himetric mapping mode EX05B is Ex05a converted to MM_HIMETRIC coordinates. The Ex05b project on the companion CD uses new class names and filenames, but the following instructions take you through modifying the Ex05a code. Like Ex05a, Ex05b performs a hit-test so that the ellipse changes color only when You Click Inside The Bounding Rectangle. 1. Use The Class View's Properties Window To Override The Virtual Onpreparedc Function. You Can Override Virtual Functions Fo r selected MFC library base classes, including Cview in the Properties window. The code wizards available from the Properties window generate the correct function prototype in the class's header file and a skeleton function in the CPP file. Select the class name Cex05aView in the Class View Right-Click ON IT, AND THEN Choose Properties. Click The Overrides Button On The Properties Window Toolbar and SELECT The onpreparedc Function in The List. Add The function.
. Visual C NET will load the implementation file so you can edit the function as shown here: Void Cex05aView :: OnPrepareDC (CDC * pDC, Cprintinfo * pInfo) {pDC-> SetMapMode (MM_HIMETRIC); CView :: OnPrepareDC (Pdc, pInfo } The application framework calls The Virtual Onpreparedc Function Just Before It Calls OnDraw. Example EX05B: Convert to MM_HIMETRIC Mapping Mode EX05B is an example of EX05A to convert to mm_himetric coordinates. EX05B project uses new class names and files in the CD of the book Name, but you can modify the EX05A code through the following instructions. Like EX05A, when you click Oll in the rectangle, the color changes, so EX05B also performs a collision test. 1. Use the properties window of the class view to overrunize the deficiency Functions onpreparedc You can select the MFC base class from the Properties window and overload virtual functions, including CView. Code wizard from the Property window generates the appropriate function prototype and generates a function of the CPP file. Select Class name Class view of CEX05AVIEW, right click and select Properties. Click the overprepAREDC function on the Properties window toolbar and select the onpreparedc function in the list. Add this function .vc . NET will load the execution file so you can edit the function, as shown below : Void CEX05AVIEW :: OnPreParedc (CDC * PDC, CPRINFO * PINFO) {PDC-> setmapmode (mm_himetric); CView :: OnPreparedc (PDC, PINFO);} The application framework will call the virtual function overpreparedc function before calling the onDraw function. 2. Edit The View Class Constructor. You Must Change The Coordinate Value for The Ellipse Rectangle. That Rectangle Is Now 4-by-4 Centimeter INSTEAD OF 200-BY-200 Pixels. N ! Ote that the y value must be negative; otherwise, the ellipse will be drawn on the "virtual screen" right above your monitor Change the values as shown here: Cex05aView :: Cex05aView (): m_rectEllipse (0,0,4000, - . 4000) {m_nColor = GRAY_BRUSH;} 3. Edit the OnLButttonDown function This function must convert the ellipse rectangle to device coordinates in order to do the hit-test Change the function as shown in the following code: Void Cex05aView :: OnLButtonDown (. Unit nflags, cpoint point) {CClientDC DC (this); onpreparedc (& DC); cRect RectDevice = m_rectellipse; DC.
LptoDP (rectDevice); if (retDevice.PtInRect (point)) {if (m_nColor == GRAY_BRUSH) {m_nColor = WHITE_BRUSH;} else {m_nColor = GARY_BRUSH;} InvalidateRect (rectDevice);}} 4. Build and run the Ex05b program . the output should look similar to the output from Ex05a, except that the ellipse size will be different. If you try using Print Preview again, the ellipse should appear much larger than it did in Ex05a. 2. edit view class constructor. You must change the coordinate value for the ellipse range. This range is now 4x4 cm instead of 200x200 pixels. Note that the Y value must be negative, otherwise this circle will draw a "virtual screen" on your monitor. Change this value code As follows: CEX05AView :: CEX05AView (): m_rectellipse (0,0,4000, -4000) {m_ncolor = gray_brush;} 3. Editing the ONLBUTTONDOWN function. This function must be converted to the equipment coordinates for collision test. Change this function code as follows: Void Cex05aView :: OnLButtonDown (UNIT nFlags, Cpoint point) {CCLientDC dc (this); OnPrepareDC (& dc); CRect rectDevice = m_rectEllipse; dc.LptoDP (rectDevice); if (retDevice.PtInRect (point)) {if (m_ncolor == gray_brush) {m_ncolor = white_brush;} else {m_ncolor = gary_brush;} invalidateecture;}} 4. Generate and run the EX05B program. In addition to the size of the ellipse, you will see similar Ex05a output. If you try to use Print preview, much larger than Ex05a see the ellipse. Creating a Scrolling View Window As the lack of scroll bars in Ex05a and Ex05b indicates, the MFC library Cview class, the base class of Cex05bView, does not directly support scrolling. Another MFC library class, CscrollView, does support scrolling. CscrollView is derived from Cview. We'll create a new program, Ex05c, that uses CscrollView in place of Cview. All the coordinate conversion code you added in Ex05b sets you up for Scrolling. The CscrollView Class Supports Scrolling from The Scroll Bars But Not from The Keyboard.
IT's Easy ENOUGH TO Add Keyboard Scrolling, SO We'll Do IT Build Scroll View Windows EX05A and EX05B are missing scrolling support, and CEX05BVIEW generated by the MFC base class CView is another MFC class that does not directly support scrolling, and CScrollView can support scrolling. CscrollView is from CView. We will create a new program EX05C, use cscrollview in CView. All coordinate conversion codes add setting your roll in EX05B. CscrollView class supports roll because of the roller strip rather than Keyboard. It is easy to do this by adding the keyboard. of the window and items at the bottom and / or on the right of the window will disappear. When you expand the window, the items will reappear. you can correctly conclude that a window is larger than the viewport that you see on the screen. The viewport does not have to be anchored at the top left of the window area, however. Through the use of the CWnd functions ScrollWindow and SetWindowOrg, the CscrollView class allows you to move the viewport anywhere within the window, including areas above and to The Left of The Origin. Scroll Bars Windows Makes I t easy to display scroll bars at the edges of a window, but Windows by itself does not make any attempt to connect those scroll bars to their window. That's where the CscrollView class fits in. CscrollView member functions process the WM_HSCROLL and WM_VSCROLL messages sent By The Scroll Bars To The View. Those Functions Move The ViewPort Wtem Housekeeping.