This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:
Logical Inches and Physical Inches on the Display
The CDC member function GetDeviceCaps() returns various display measurements that are important to your graphics programming. The six described below provide information about the display size. The values listed are for a typical display card configured for a resolution of 640-by-480 pixels with Microsoft Windows NT 4.0.
The indexes HORZSIZE and VERTSIZE represent the physical dimensions of your display. These indexes might not be true since Windows doesn't know what size display you have connected to your video adapter. You can also calculate a display size by multiplying HORZRES and VERTRES by LOGPIXELSX and LOGPIXELSY, respectively. The size calculated this way is known as the logical size of the display. Using the values above and the fact that there are 25.4 millimeters per inch, we can quickly calculate the two display sizes for a 640-by-480 pixel display under Windows NT 4.0. The physical display size is 12.60-by-9.45 inches, and the logical size is 6.67-by-5.00 inches. So the physical size and the logical size need not be the same.
For Windows NT 4.0, it turns out that HORZSIZE and VERTSIZE are independent of the display resolution, and LOGPIXELSX and LOGPIXELSY are always 96. So the logical size changes for different display resolutions, but the physical size does not. For Windows 95, the logical size and the physical size are equal, so both change with the display resolution. At a resolution of 640-by-480 pixels with Windows 95, HORZSIZE is 169 and VERTSIZE is 127. Whenever you use a fixed mapping mode such as MM_HIMETRIC or MM_TWIPS, the display driver uses the physical display size to do the mapping. So, for Windows NT, text is smaller on a small monitor; but that's not what you want. Instead, you want your font sizes to correspond to the logical display size, not the physical size. You can invent a special mapping mode, called logical twips, for which one logical unit is equal to 1/1440 logical inch. This mapping mode is independent of the operating system and display resolution and is used by programs such as Microsoft Word. Here is the code that sets the mapping mode to logical twips:
From the Windows Control Panel, you can adjust both the display font size and the display resolution through the Appearance and Settings of the Display Properties shown below. If you change the display font size from the default 100 percent to 200 percent, HORZSIZE becomes 160, VERTSIZE becomes 120, and the dots-per-inch value becomes 192. In that case, the logical size is divided by 2, and all text drawn with the logical twips mapping mode is doubled in size.
Figure 1: Adjusting the display’s font size and resolution.
Computing Character Height
Five font height measurement parameters are available through the CDC function GetTextMetrics(), but only three are significant. Figure 2 shows the important font measurements. The tmHeight parameter represents the full height of the font, including descenders (for the characters g, j, p, q, and y) and any diacritics that appear over capital letters. The tmExternalLeading parameter is the distance between the top of the diacritic and the bottom of the descender from the line above. The sum of tmHeight and tmExternalLeading is the total character height. The value of tmExternalLeading can be 0.
Figure 2: Font height measurements.
You would think that tmHeight would represent the font size in points. Wrong! Another GetTextMetrics() parameter, tmInternalLeading, comes into play. The point size corresponds to the difference between tmHeight and tmInternalLeading. With the MM_TWIPS mapping mode in effect, a selected 12-point font might have a tmHeight value of 295 logical units and a tmInternalLeading value of 55. The font's net height of 240 corresponds to the point size of 12.
The MYMFC4 Example
This example sets up a view window with the logical twips mapping mode. A text string is displayed in 10 point sizes with the Arial TrueType font. Here are the steps for building the application:
Run AppWizard to generate the MYMFC4 project. Start by choosing New from the File menu and then select MFC AppWizard (exe) on the Project tab. Select Single Document and deselect Printing And Print Preview and ActiveX Controls; accept all the other default settings. The options and the default class names are shown in the following Figure.
Figure 3: MYMFC4 project summary.
Use ClassWizard to override the OnPrepareDC() function in the CMymfc4View class. By clicking the Edit Code button, edit the code in mymfc4View.cpp as follows:
Figure 4: Using ClassWizard to override the OnPrepareDC() function.
void CMymfc4View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
Add a private ShowFont() helper function to the view class as shown below. In the ClassView, select the CMymfc4View class and right click your mouse. Select Add Member Function… context menu and fill up the Function Type and Function Declaration. As usual, you can add manually by opening the mymfc4View.h:
Figure 5: Adding a member function using ClassView.
Figure 6: Member function type and declaration.
void ShowFont(CDC* pDC, int& nPos, int nPoints);
Then add the function itself in mymfc4View.cpp:
void CMymfc4View::ShowFont(CDC* pDC, int& nPos, int nPoints)
fontText.CreateFont(-nPoints * 20, 0, 0, 0, 400, FALSE, FALSE, 0,
DEFAULT_PITCH | FF_SWISS, "Arial");
CFont* pOldFont = (CFont*) pDC->SelectObject(&fontText);
TRACE("points = %d, tmHeight = %d, tmInternalLeading = %d,"
" tmExternalLeading = %d\n", nPoints, tm.tmHeight,
strText.Format("This is %d-point Arial", nPoints);
sizeText = pDC->GetTextExtent(strText);
TRACE("string width = %d, string height = %d\n", sizeText.cx, sizeText.cy);
pDC->TextOut(0, nPos, strText);
nPos -= tm.tmHeight + tm.tmExternalLeading;
Edit the OnDraw() function in mymfc4View.cpp. AppWizard always generates a skeleton OnDraw() function for your view class. Find the function, and replace the code with the following:
void CMymfc4View::OnDraw(CDC* pDC)
int nPosition = 0;
for (int i = 6; i <= 24; i += 2)
ShowFont(pDC, nPosition, i);
TRACE("LOGPIXELSX = %d, LOGPIXELSY = %d\n",
TRACE("HORZSIZE = %d, VERTSIZE = %d\n",
TRACE("HORZRES = %d, VERTRES = %d\n",
Build and run the MYMFC4 program. You must run the program from the debugger if you want to see the output from the TRACE statements. You can choose Go from the Start Debug submenu of the Build menu in Visual C++, or click the following button on the Build toolbar, .
Figure 7: The Visual C++ program debug menu, tracing the TRACE.
The output (assuming the use of a standard VGA card) looks like the following.
Figure 8: MYMFC4 program output.
Notice that the output string sizes don't quite correspond to the point sizes. This discrepancy results from the font engine's conversion of logical units to pixels. The program's trace output, partially shown below, shows the printout of font metrics. The numbers depend on your display driver and your video driver.
Figure 9: The Visual C++ Debug window messages generated using the TRACE.
The following is a discussion of the important elements in the MYMFC4 example.
Setting the Mapping Mode in the OnPrepareDC() Function
The application framework calls OnPrepareDC() prior to calling OnDraw(), so the OnPrepareDC() function is the logical place to prepare the device context. If you had other message handlers that needed the correct mapping mode, those functions would have contained calls to OnPrepareDC().
The ShowFont() Private Member Function
ShowFont() contains code that is executed 10 times in a loop. With C, you would have made this a global function, but with C++ it's better to make it a private class member function, sometimes known as a helper function. This function creates the font, selects it into the device context, prints a string to the window, and then deselects the font. If you choose to include debug information in the program, ShowFont() also displays useful font metrics information, including the actual width of the string.
This call includes lots of parameters, but the important ones are the first two: the font height and width. A width value of 0 means that the aspect ratio of the selected font will be set to a value specified by the font designer. If you put a nonzero value here, as you'll see in the next example, you can change the font's aspect ratio. If you want your font to be a specific point size, the CreateFont() font height parameter (the first parameter) must be negative. If you're using the MM_TWIPS mapping mode for a printer, for example, a height parameter of -240 ensures a true 12-point font, with tmHeight - tmInternalLeading = 240. A +240 height parameter gives you a smaller font, with tmHeight = 240.
Continue on next module...part 3
Further reading and digging:
MSDN MFC 9.0 class library online documentation - latest version.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.