window程序设计上有这么一段
SetMapMode(hdc,MM_ISOTROPIC);
SetWindowExtEx(hdc,1000,1000,NULL);
SetViewportExtEx(hdc,cxClient/2,-cyClient/2,NULL);  // 这个视口的范围是(0,0)-(cxClient/2,-                                                      cyClient/2)?
SetViexportOrgEx(hdc,cxClient/2,cyClient/2,NULL);
结果是在客户区的中间形成一个完整的四相限坐标系? 清具体解释一下,就和后面那个话表的小程序中用到的一样,还有其他方法吗? 像这样行不行,
SetMapMode(hdc,MM_ISOTROPIC);
SetWindowExtEx(hdc,1000,1000,NULL);
SetViexportOrgEx(hdc,-cxClient/2,-cyClient/2,NULL);和上面有什么不同 ?

解决方案 »

  1.   

    我举的例子写错了 本来像的是这样
    SetMapMode(hdc,MM_ISOTROPIC);
    SetWindowExtEx(hdc,1000,1000,NULL);
    SetViexportOrgEx(hdc,-cxClient/2,cyClient/2,NULL);   //
    这样能实现书上的效果吗
      

  2.   

    The Mapping Mode
    Without a doubt, the aspect of GDI programming that new Windows programmers find the most confusing is the mapping mode. Simply put, the mapping mode is the attribute of the device context that governs how logical coordinates are translated into device coordinates. Logical coordinates are the coordinates you pass to CDC output functions. Device coordinates are the corresponding pixel positions within a window. When you call the Rectangle function like this: dc.Rectangle (0, 0, 200, 100); 
    you're not necessarily telling the GDI to draw a rectangle that's 200 pixels wide and 100 pixels tall; you're telling it to draw a rectangle that's 200 units wide and 100 units tall. In the default mapping mode, MM_TEXT, it just so happens that 1 unit equals 1 pixel. But in other mapping modes, logical units are translated into device units differently. In the MM_LOENGLISH mapping mode, for example, 1 unit equals 1/100 of an inch. Therefore, drawing a rectangle that measures 200 units by 100 units in the MM_LOENGLISH mapping mode produces a 2-inch by 1-inch rectangle. Using a non-MM_TEXT mapping mode is a convenient way to scale your output so that sizes and distances are independent of the output device's physical resolution. Windows supports eight different mapping modes. Their properties are summarized in the following table. GDI Mapping Modes Mapping Mode  Distance Corresponding to One Logical Unit  Orientation of the x and y Axes 
    MM_TEXT 1 pixel  
    MM_LOMETRIC 0.1 mm  
    MM_HIMETRIC  0.01 mm  
    MM_LOENGLISH  0.01 in.  
    MM_HIENGLISH 0.001 in.  
    MM_TWIPS  1/1440 in. (0.0007 in.)  
    MM_ISOTROPIC User-defined (x and y scale identically)  User-defined 
    MM_ANISOTROPIC User-defined (x and y scale independently) User-defined 
    When you draw in the MM_TEXT mapping mode, you're using the coordinate system shown in Figure 2-1. The origin is in the upper left corner of the window, the positive x axis points to the right, the positive y axis points downward, and 1 unit equals 1 pixel. If you switch to one of the "metric" mapping modes—MM_LOENGLISH, MM_HIENGLISH, MM_LOMETRIC, MM_HIMETRIC, or MM_TWIPS—the y axis flips so that positive y points upward and logical units are scaled to represent real distances rather than raw pixel counts. The origin, however, remains in the upper left corner. One thing to remember when using a metric mapping mode is that you must use negative y values if you want to see your output. The statement dc.Rectangle (0, 0, 200, 100);
      

  3.   

    draws a 200-pixel by 100-pixel rectangle in the MM_TEXT mapping mode. The same statement produces no output in the MM_LOENGLISH mapping mode because positive y coordinates lie outside the visible part of the window. To make the rectangle visible, you must negate the y coordinates, as shown here: dc.Rectangle (0, 0, 200, -100); 
    If you switch to a non-MM_TEXT mapping mode and suddenly your application's output is no longer visible, check the sign of your y coordinates. Positive y coordinates will be the problem almost every time.  Figure 2-1. The MM_TEXT coordinate system. The default mapping mode is MM_TEXT. If you want to use one of the other mapping modes, you must call CDC::SetMapMode to change the mapping mode. The following statements switch to the MM_LOMETRIC mapping mode and draw an ellipse whose major axis is 5 centimeters long and whose minor axis measures 3 centimeters: dc.SetMapMode (MM_LOMETRIC);
    dc.Ellipse (0, 0, 500, -300); 
    You can see that there's really nothing tricky about mapping modes. Things get slightly more complicated when you use the MM_ISOTROPIC and MM_ANISOTROPIC modes and when you do hit-testing on objects drawn in non-MM_TEXT mapping modes, but even that doesn't have to be difficult. The MM_ISOTROPIC and MM_ANISOTROPIC mapping modes are discussed in the next section. One thing to keep in mind when you use the metric mapping modes is that on display screens, 1 logical inch usually doesn't equal 1 physical inch. In other words, if you draw a line that's 100 units long in the MM_LOENGLISH mapping mode, the line probably won't be exactly 1 inch long. The reason? Windows doesn't know the physical resolution of your monitor—the number of dots per inch (dpi) it's capable of displaying horizontally and vertically. (This might change in a future version of Windows.) The same is not true of printers and other hardcopy devices, however. The printer driver knows that a 600 dpi laser printer can print exactly 600 dots per inch, so a 100-unit line drawn in the MM_LOENGLISH mapping mode will measure exactly 1 inch on the printed page. Programmable Mapping Modes
    The MM_ISOTROPIC and MM_ANISOTROPIC mapping modes differ from the other mapping modes in one important respect: It's you, not Windows, who determines how logical coordinates are converted into device coordinates. For this reason, these mapping modes are sometimes called the "roll-your-own" or "programmable" mapping modes. Want a mapping mode in which 1 unit equals 1 centimeter? No problem: Just use the MM_ANISOTROPIC mapping mode and set its scaling parameters accordingly. The most common use for the MM_ISOTROPIC and MM_ANISOTROPIC mapping modes is for drawing output that automatically scales to match the window size. The following code fragment uses the MM_ANISOTROPIC mapping mode to draw an ellipse that touches all four borders of the window in which it is drawn: CRect rect;
    GetClientRect (&rect);
    dc.SetMapMode (MM_ANISOTROPIC);
    dc.SetWindowExt (500, 500);
    dc.SetViewportExt (rect.Width (), rect.Height ());
    dc.Ellipse (0, 0, 500, 500); 
    See how it works? No matter what physical size the window is, you've told Windows that the window's logical size is 500 units by 500 units. Therefore, a bounding box that stretches from (0,0) to (500,500) encompasses the entire window. Initializing a device context in this way places the origin at the upper left corner of the window and orients the axes so that positive x points to the right and positive y points downward. If you'd rather have the y axis point upward (as it does in the metric mapping modes), you can reverse its direction by negating the y value passed to either SetWindowExt or SetViewportExt: CRect rect;
    GetClientRect (&rect);
    dc.SetMapMode (MM_ANISOTROPIC);
    dc.SetWindowExt (500, -500);
    dc.SetViewportExt (rect.Width (), rect.Height ());
    dc.Ellipse (0, 0, 500, -500); 
    Now you must use negative y coordinates to draw in the window. Only the MM_ISOTROPIC and MM_ANISOTROPIC mapping modes allow the directions of the x and y axes to be reversed. That's why the table in the previous section listed these two mapping modes' axis orientations as user defined. The only difference between the MM_ISOTROPIC and MM_ANISOTROPIC mapping modes is that in the former, the scaling factors for the x and y directions are always the same. In other words, 100 horizontal units equals the same physical distance as 100 vertical units. Isotropic means "equal in all directions." The MM_ISOTROPIC mapping mode is ideal for drawing circles and squares. The following code draws a circle that spans the width or height of a window, whichever is smaller: CRect rect;
    GetClientRect (&rect);
    dc.SetMapMode (MM_ISOTROPIC);
    dc.SetWindowExt (500, 500);
    dc.SetViewportExt (rect.Width (), rect.Height ());
    dc.Ellipse (0, 0, 500, 500);
      

  4.   

    As far as Windows is concerned, the window's logical size is once again 500 units by 500 units. But now the GDI takes the output device's aspect ratio into consideration when converting logical units to device units. Chapter 14's Clock program uses the MM_ISOTROPIC mapping mode to draw a round clock face and to automatically scale the clock size to the window size. Without the MM_ISOTROPIC mapping mode, Clock would have to do all of the scaling manually. Let's talk a bit about the SetWindowExt and SetViewportExt functions. Officially, SetWindowExt sets the "window extents" and SetViewportExt sets the "viewport extents." Think of a window as something whose size is measured in logical units and a viewport as something whose size is measured in device units, or pixels. When Windows converts between logical coordinates and device coordinates, it uses a pair of formulas that factor in the window's logical dimensions (the window extents) and its physical dimensions (the viewport extents) as well as the location of the origin. When you set the window extents and viewport extents, you're effectively programming in your own scaling parameters. Generally, the viewport extents are simply the size (in pixels) of the window you're drawing in and the window extents are the window's desired size in logical units. One caveat regarding the use of SetWindowExt and SetViewportExt is that in the MM_ISOTROPIC mapping mode, you should call SetWindowExt first. Otherwise, a portion of the window's client area might fall outside the window's logical extents and become unusable. In the MM_ANISOTROPIC mapping mode, it doesn't matter which are set first—the window extents or the viewport extents. Coordinate Conversions
    You can translate logical coordinates to device coordinates using the CDC::LPtoDP function. Conversely, you can translate device coordinates to logical coordinates with CDC::DPtoLP. Let's say you want to know where the center of a window is in device coordinates. All you have to do is halve the window's pixel width and height. CWnd::GetClientRect returns a window's pixel dimensions. CRect rect;
    GetClientRect (&rect);
    CPoint point (rect.Width () / 2, rect.Height () / 2); 
    If you want to know where the center point is in MM_LOENGLISH units, however, you need DPtoLP: CRect rect;
    GetClientRect (&rect);
    CPoint point (rect.Width () / 2, rect.Height () / 2);
    CClientDC dc (this);
    dc.SetMapMode (MM_LOENGLISH);
    dc.DPtoLP (&point); 
    When DPtoLP returns, point holds the coordinates of the center point in logical (that is, MM_LOENGLISH) coordinates. If, on the other hand, you want to know the pixel coordinates of the point whose MM_LOENGLISH coordinates are (100,100), you use LPtoDP: CPoint point (100, 100);
    CClientDC dc (this);
    dc.SetMapMode (MM_LOENGLISH);
    dc.LPtoDP (&point); 
    One situation in which LPtoDP and DPtoLP are indispensable is when you're performing hit-testing in response to mouse clicks. Mouse clicks are always reported in device coordinates, so if you've drawn a rectangle in MM_LOENGLISH coordinates and you want to know whether a mouse click occurred inside that rectangle, you must either convert the rectangle's coordinates to device coordinates or convert the click coordinates to logical coordinates. Otherwise, you'll be comparing apples and oranges. Moving the Origin
    By default, a device context's origin is in the upper left corner of the display surface. Even if you change the mapping mode, the origin remains in the upper left corner. But just as you can change the mapping mode, you can also move the origin. MFC's CDC class provides two functions for moving the origin. CDC::SetWindowOrg moves the window origin, and CDC::SetViewportOrg moves the viewport origin. You'll normally use one but not both. Using both can be very confusing. Suppose you'd like to move the origin to the center of the window so that you can center what you draw by centering your output around the point (0,0). Assuming that dc is a device context object, here's one way to do it: CRect rect;
    GetClientRect (&rect);
    dc.SetViewportOrg (rect.Width () / 2, rect.Height () / 2); 
    Here's another way to accomplish the same thing, assuming that you're working in the MM_LOENGLISH mapping mode: CRect rect;
    GetClientRect (&rect);
    CPoint point (rect.Width () / 2, rect.Height () / 2);
    dc.SetMapMode (MM_LOENGLISH);
    dc.DPtoLP (&point);
    dc.SetWindowOrg (-point.x, -point.y); 
    It's easy to get SetViewportOrg and SetWindowOrg confused, but the distinction between them is actually quite clear. Changing the viewport origin to (x,y) with SetViewportOrg tells Windows to map the logical point (0,0) to the device point (x,y). Changing the window origin to (x,y) with SetWindowOrg does essentially the reverse, telling Windows to map the logical point (x,y) to the device point (0,0)—the upper left corner of the display surface. In the MM_TEXT mapping mode, the only real difference between the two functions is the signs of x and y. In other mapping modes, there's more to it than that because SetViewportOrg deals in device coordinates and SetWindowOrg deals in logical coordinates. You'll see examples of how both functions are used later in this chapter. As a final example, suppose you're drawing in the MM_HIMETRIC mapping mode, where 1 unit equals 1/100 of a millimeter, positive x points to the right, and positive y points upward, and you'd like to move the origin to the lower left corner of the window. Here's an easy way to do it: CRect rect;
    GetClientRect (&rect);
    dc.SetViewportOrg (0, rect.Height ()); 
    Now you can draw with positive x and y values using coordinates relative to the window's lower left corner. A Final Word on Coordinate Systems
    When you talk about mapping modes, window origins, viewport origins, and other idioms related to the GDI's handling of coordinates, it's easy to get tangled up in the terminology. Understanding the difference between the device coordinate system and the logical coordinate system might help clear some of the cobwebs. In the device coordinate system, distances are measured in pixels. The device point (0,0) is always in the upper left corner of the display surface, and the positive x and y axes always point right and downward. The logical coordinate system is altogether different. The origin can be placed anywhere, and both the orientation of the x and y axes and the scaling factor (the number of pixels that correspond to 1 logical unit) vary with the mapping mode. To be precise, they vary with the window extents and the viewport extents. You can change these extents in the MM_ISOTROPIC and MM_ANISOTROPIC mapping modes but not in the other mapping modes. You'll sometimes hear Windows programmers talk about "client coordinates" and "screen coordinates." Client coordinates are simply device coordinates relative to the upper left corner of a window's client area. Screen coordinates are device coordinates relative to the upper left corner of the screen. You can convert from client coordinates to screen coordinates and vice versa using the CWnd::ClientToScreen and CWnd::ScreenToClient functions. Why these functions are useful will become apparent to you the first time you call a Windows function that returns screen coordinates and you pass them to a function that requires client coordinates, or vice versa.