Webocreation

Monday, November 23, 2009

Drawing Graphics and Text to the Screen

Lab 7.1: Drawing Graphics and Text to the Screen
In this lab, you will create a simple editor of shapes and text. This editor allows the user to add, delete, and duplicate polygon and text items.

Users can add a polygon or text item through one of three mechanisms: menu selection, toolbar, or context-sensitive menu. They can delete or duplicate a polygon or text item through the context-sensitive menu. They can also place items at the top or the bottom of the Z-order.

The default polygon is a triangle, but users can modify the shape of the polygon. They can add and delete vertices or additional points to the polygon. They can add a vertex by dragging outward from the side of the polygon. They can delete a vertex by right-clicking on the polygon near the target vertex. Users can also modify the polygon's color, transparency, and outline properties by right-clicking the item and clicking the Properties command.

Users can customize the color and font of text items and they can alter the text string itself.

Finally, users can save and load their data to disk. Zooming and panning capabilities are also implemented.

To see a demonstration of the lab solution, click this icon.

Estimated time to complete this lab: 120 minutes

To complete the exercises in this lab, you must have the required software. For detailed information about the labs and setup for the labs, see Labs in this course.

Objectives

After completing this lab, you will be able to:

® Implement an application's OnDraw member function.
® Use the CPen, CFont, and CBrush stock GDI objects.
® Manipulate mapping modes.
® Set viewport and window origins.

Prerequisites

There are no prerequisites for this lab.

Exercises

The following exercises provide practice with the concepts and techniques covered in this chapter:
® Exercise 1: Coding the OnDraw Function
In this exercise you will add code to the view’s OnDraw function. Once this code is added, you will be able to add generic items to the document.
® Exercise 2: Implementing the Polygon Draw Function
In this exercise you will replace the code within the document's member function, NewPolygon, with code to create an instance of the CPolygon class. Also, you will implement the CPolygon draw function.
® Exercise 3: Implementing the Text Draw Function
In this exercise you will replace the code within the document's member function, NewText, with code to create an instance of the CText class. Also, you will implement the CText draw function.
® Exercise 4: Adding Zoom Capabilities
In this exercise you will implement a zoom capability on the document by creating code to use a scaling variable. The scale, a member variable of the view, is the ratio of item size to pixel size. This scale is used to generate the proper viewport and window extents for the DC.

Exercise 1: Coding the OnDraw Function

The code that forms the basis for this exercise is in \Labs\Ch07\Lab01\Baseline.
In this exercise you will add code to the view's OnDraw function. Once this code is added you will be able to add generic items to the document; exercises later in this chapter will add specific drawing support for the polygon and text types.

Add generic drawing capability to the OnDraw function
1. Copy the baseline project.
2. Edit the CPolyEditView::OnDraw function.
3. Within the empty brackets, add the following code to call the document's Draw function. When this is supplied, the user-defined function will draw all document-related data.

pDoc->draw(pDC);
4. Add code to draw the document's logical origin and the view window's inner rectangle. Whether or not these are drawn is based on the view's two member variables, m_bShowOrigin and m_bShowInnerBox.
if (m_bShowOrigin)
pDoc->drawOrigin(pDC);
if (m_bShowInnerBox)
drawInnerBox(pDC);
5. Build and run the application.
6. To test this version of the application, on the Edit menu, click Add Polygon.

This adds a movable rectangle at the center of the client window. Once one or more items are created, you can use the context menu to duplicate, delete, and move items within the document's Z-order. Use the View menu to turn off drawing the document's origin and the view’s inner window.

You can find the code for this completed exercise in \Labs\Ch07\Lab01\Ex01.

Exercise 2: Implementing the Polygon Draw Function

Continue with the files you created in Exercise 1, or if you do not have a starting point for this exercise, the code that forms the basis for this exercise is in \Labs\Ch07\Lab01\Ex01.

In this exercise you will replace the code within the document's member function, NewPolygon, with code to create an instance of the CPolygon class. Also, you will implement the CPolygon draw function.

Add code to create new polygons

1. Remove the existing code within the inner brackets in the CPolyEditDoc::NewPolygon function.
2. Create a new polygon and add three points to the object:
// Create a new default polygon.
CPolygon* pPolygon= new CPolygon;

// Add some points

pPolygon->Add(CPoint(-100, -100));
pPolygon->Add(CPoint(0, 100));
pPolygon->Add(CPoint(100, -100));
3. Specify the polygon's position by adjusting all points of the polygon by adding an offset to them. Then add the polygon to the document’s existing collection of items. The variable, pos, was passed in as an argument to the NewPolygon function and specifies the logical position of the polygon in the drawing.
// Offset it by the specified amount.
pPolygon->Offset(pos);

// Add the polygon to the document.

POSITION position= m_items.AddTail(pPolygon);
Extend the CPolygon Draw functionality

1. Edit the CPolygon draw function, and then construct a CPen object using the object's line style, line thickness, and line color.
CPen pen(m_styleLine,m_thickLine,m_colorLine);
2. Create the polygon's brush by initializing a LOGBRUSH structure and then calling the CBrush CreateBrushIndirect function. Use the polygon's member variables to initialize the structure.

CBrush brush;
LOGBRUSH BrushStruct;
BrushStruct.lbColor= m_colorBrush;
BrushStruct.lbStyle= m_styleBrush;
BrushStruct.lbHatch= m_hatchBrush;
brush.CreateBrushIndirect(&BrushStruct);
3. For a hatched brush style, have the brush's hatch origin follow the polygon as it is being moved. Do this by fixing the brush origin to the polygon's first point. Also, set the DC's background mode to transparent so that those objects behind the polygon are visible when a hatch brush is selected.
// Set the brush origin to the polygon’s first point.
pDC->SetBrushOrg(m_pts[0].x % 8, m_pts[0].y % 8);

// Should only be evident for hatched brushes

pDC->SetBkMode(TRANSPARENT);

4. Select the pen and brush into the DC's context while saving the old values.

CPen* pOldPen= pDC->SelectObject(&pen);
CBrush* pOldBrush= pDC->SelectObject(&brush);
5. Call the DC's Polygon method on the polygon's point data to draw the polygon.
pDC->Polygon(GetData(), GetSize());
6. Reselect the old pen and brush into the DC’s context.
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
7. The complete code for the Draw function is shown in the following example code:
void CPolygon::draw(CDC * pDC)
{
CPen pen(m_styleLine,m_thickLine,m_colorLine);
CBrush brush;
LOGBRUSH BrushStruct;
BrushStruct.lbColor= m_colorBrush;
BrushStruct.lbStyle= m_styleBrush;
BrushStruct.lbHatch= m_hatchBrush;
brush.CreateBrushIndirect(&BrushStruct);

// so that hatch moves with the polygon

pDC->SetBrushOrg(m_pts[0].x % 8, m_pts[0].y % 8);

// Should only be evident for hatched brushes

pDC->SetBkMode(TRANSPARENT);

CPen* pOldPen= pDC->SelectObject(&pen);

CBrush* pOldBrush= pDC->SelectObject(&brush);

pDC->Polygon(GetData(), GetSize());

pDC->SelectObject(pOldPen);

pDC->SelectObject(pOldBrush);

}

8. Build and run the application.

Test it by creating several polygons. Change the shape of a polygon by dragging a vertex. Add a vertex by dragging the mouse near one of its borders. Try the different pen and brush styles by right-clicking a polygon and clicking the Properties command.

You can find the code for this completed exercise in \Labs\Ch07\Lab01\Ex02.

Exercise 3: Implementing the Text Draw Function

Continue with the files you created in Exercise 2 or, if you do not have a starting point for this exercise, the code that forms the basis for this exercise is in \Labs\Ch07\Lab01\Ex02.

In this exercise you will replace the code within the document's member function, NewText, with code to create an instance of the CText class. Also, you will implement the CText draw function.

Create a new text object

1. Remove the existing code within the inner brackets of the CPolyEditDoc::NewText function.
2. Create a new CText object and set its position by calling the CText member function, Offset.
// Create a new text item.
CText* pText= new CText;

// Adjust position

pText->Offset(pos);
3. Add the object to the existing collection of items.
// add to collection
m_items.AddTail(pText);

Draw the new text object
1. Edit the CText draw function. Set the DC's background mode to transparent so those items behind the text are visible. Also, set the text color to the CText object's color.
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(m_color);
2. Construct a default CFont object. Use the CText member variable to initialize the CFont object. Select the font into the DC's context. Write the text out at the object's position.
CFont font;
font.CreateFontIndirect(&m_lf);
CFont* pOldFont= pDC->SelectObject(&font);
pDC->TextOut(m_pos.x, m_pos.y, m_string);

3. Save the text's extent for later processing and reselect the old font.

// Save this value for HitTest operation.
m_sz= pDC->GetTextExtent(m_string);

pDC->SelectObject(pOldFont);

4. Build and run the application. Test it by creating several text objects. Modify the text message by right-clicking it and clicking the Properties command. Also try modifying the font, color, and point size.

You can find the code for this completed exercise in \Labs\Ch07\Lab01\Ex03.

Exercise 4: Adding Zoom Capabilities

Continue with the files you created in Exercise 3 or, if you do not have a starting point for this exercise, the code that forms the basis for this exercise is in \Labs\Ch07\Lab01\Ex03.

In this exercise you will implement a zoom capability on the document by creating code to use a scaling variable. The scale, a member variable of the view, is the ratio of item size to pixel size. This scale is used to generate the proper viewport and window extents for the DC.

Enable zooming

1. Edit the CPolyEditView constructor. Replace the following code:
m_minScale = m_maxScale = 1.0;
with the code below:

m_minScale = MIN_SCALE;
m_maxScale = MAX_SCALE;

This change will allow for a range of scales, which in turn will enable the Zoom In and Zoom Out menus and toolbar buttons. Examine the OnUpdate handlers for these menus to see how this is done.
2. Edit the CPolyEditView SetView function, a user-defined function for setting the DC's origins and extents. Notice that the passed parameters specify the center of the view window (in logical units) as well as the scale. Delete the code within the innermost brackets of the function.
3. Add the following code to obtain the size of the viewing window. This size will be used to determine the center of the view (in device units).
// Get view coordinates
CRect rect;
GetClientRect(&rect);
4. Set the mapping mode.
// Set the mapping mode
pDC->SetMapMode(MM_ISOTROPIC);
5. Calculate the window and viewport extents based upon the scale. Since the scale can be a less than 1 as well as beyond the maximum allowed extent value, you need to check the scale and then adjust the extent values as required.
// Determine the extents based upon scale.
int WinExt,ViewExt;
if (scale > THRES_SCALE)
{
WinExt= (int) THRES_SCALE;
ViewExt= (int) (scale/WinExt); // parentheses required!
}
else if (scale >= 1.0)
{
WinExt= (int) scale;
ViewExt= (int) 1.0;
}
else if (scale >= 1.0/THRES_SCALE)
{
WinExt= (int) 1.0;
ViewExt= (int) (1/scale);
}
else
{
ViewExt= (int) THRES_SCALE;
WinExt= (int) (scale/ViewExt);
}

6. Set the origin and extent for both the viewport and the window.
// Set the origins
pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);
pDC->SetWindowOrg(x,y);

// SetWindowExt must come before SetViewportExt.

pDC->SetWindowExt(WinExt,WinExt);
pDC->SetViewportExt(ViewExt, -ViewExt);
// 2nd parameter is negative to get positive y axis going up.
7. Build and run the application.

Test the zoom capability by clicking first the Zoom Out toolbar button several times, and then the Zoom In toolbar button several times. Notice how the origin lines get thicker as you zoom in. This is because the line thickness is specified as a 1. A thickness of zero would always keep its width to one pixel wide.

You can find the code for this completed exercise in \Labs\Ch07\Lab01\Ex04.

No comments:

Post a Comment