📄 ch18.htm
字号:
11: pStartPoint.x = (m_iRadius / 2);12: pStartPoint.y = (m_iRadius / 2);13: // Set the origination point14: org.x = m_pCenter.x + (m_iRadius / 2);15: org.y = m_pCenter.y + m_iRadius;16: // Set the viewport origination point17: pDC->SetViewportOrg(org.x, org.y);18: 19: CPoint pEndPoint;20: // Calculate the angle of the next line21: double nRadians = (double) (m_nMinute * 6) * 0.017453292;22: // Set the end point of the line23: pEndPoint.x = (int) (m_iRadius * sin(nRadians));24: pEndPoint.y = (int) (m_iRadius * cos(nRadians));25: 26: 27: // Create the pen to use28: CPen pen(PS_SOLID, 0, m_crColors[m_crColor]);29: // Select the pen for use30: CPen* pOldPen = pDC->SelectObject(&pen);31: 32: // Move to the starting point33: pDC->MoveTo (pEndPoint);34: // Draw the line to the end point35: pDC->LineTo (pStartPoint);</PRE><PRE>36: </PRE><PRE>37: // Reselect the previous pen38: pDC->SelectObject(&pOldPen);39: 40: // Release the device context41: m_pViewWnd->ReleaseDC(pDC);42: 43: // Increment the minute44: if (++m_nMinute == 60)45: {46: // If the minutes have gone full circle, reset to 047: m_nMinute = 0;48: // Increment the color49: if (++m_crColor == 8)50: // If we've gone through all colors, start again51: m_crColor = 0;52: }53: }</PRE><P>That was quite a bit of code to type. What does it do? Well, to understand whatthis function is doing, and how it's going to make your spinner draw a color wheelon the window, let's take a closer look at the code.</P><P>To make efficient use of the spinner by the different threads, it'll only drawone line each time the function is called. This function will be called 60 timesfor each complete circle, once for each "minute" in the clockwise rotation.Each complete rotation will cause the spinner to switch to the next color in thecolor table.</P><P>One of the first things that you need to do in order to perform any drawing onthe window is get the device context of the window. You do this by calling the GetDCfunction on the view object pointer:</P><P><PRE>CDC *pDC = m_pViewWnd->GetDC();</PRE><P>This function returns a CDC object pointer, which is an MFC class that encapsulatesthe device context.</P><P>Once you have a pointer to the device context, you can call its member function,SetMapMode, to set the mapping mode:</P><P><PRE>pDC->SetMapMode (MM_LOENGLISH);</PRE><P>The mapping mode determines how the x and y coordinates are translated into positionson the screen. The MM_LOENGLISH mode converts each logical unit to 0.01 inch on thescreen. There are several different mapping modes, each converting logical unitsto different measurements on the screen.</P><P>At this point, you start preparing to draw the current line for the color wheel.You start by calculating the starting point for the line that will be drawn. Thispoint will be consistent for all lines drawn by the spinner object. After you calculatethe starting point for the line, you calculate the position of the viewport. Theviewport is used as the starting point for the coordinates used for drawing.</P><BLOCKQUOTE> <P><HR><STRONG>NOTE:</STRONG> The starting point for the line to be drawn is calculated in an off-center position. If you want the starting point for the lines to be in the center of the color wheel, set both the x and y coordinates of the starting point to 0.<HR></BLOCKQUOTE><P>Once the viewport origination point is calculated, use the SetViewportOrg functionto set the viewport:</P><P><PRE>pDC->SetViewportOrg(org.x, org.y);</PRE><P>Now that you've got the drawing area specified, and the starting point for theline that you are going to be drawing, you need to figure out where the other endof the line will be. You'll perform this calculation using the following three linesof code:</P><P><PRE>double nRadians = (double) (m_nMinute * 6) * 0.017453292;pEndPoint.x = (int) (m_iRadius * sin(nRadians));pEndPoint.y = (int) (m_iRadius * cos(nRadians));</PRE><P>In the first of these calculations, convert the minutes into degrees, which canthen be fed into the sine and cosine functions to set the x and y coordinates todraw a circle. This sets the end point of the line that will be drawn.</P><P>Now that you've figured out the starting and ending points of the line, you'llcreate a pen to use in drawing the line:</P><P><PRE>CPen pen(PS_SOLID, 0, m_crColors[m_crColor]);</PRE><P>You've specified that the pen will be solid and thin, and you are picking thecurrent color from the color table. Once you create the pen to use, select the penfor drawing, being sure to capture the current pen as the return value from the devicecontext object:</P><P><PRE>CPen* pOldPen = pDC->SelectObject(&pen);</PRE><P>Now you are ready to draw the line, which is done using the MoveTo and LineTofunctions that you're well familiar with by now. Once the line is drawn, releasethe device context so that you don't have a resource leak in your application:</P><P><PRE>m_pViewWnd->ReleaseDC(pDC);</PRE><P>At this point, you've drawn the line, so all that's left to do is increment theminute counter, resetting it if you've made it all the way around the circle. Eachtime you complete a circle, you increment the color counter until you've gone throughall eight colors, at which time you reset the color counter.</P><P>In order to be able to use the trigonometric functions in this function, includethe math.h header file in the Spinner class source file. To add this, scroll up tothe top of the source code file and add another #include line, specifying the math.hheader file as the file to be included, as in Listing 18.5.</P><P><H4>LISTING 18.5. THE CSpinner SOURCE FILE.</H4><PRE> 1: // Spinner.cpp : implementation of the CSpinner class 2: // 3: ////////////////////////////////////////////////////////////////////// 4: 5: #include "stdafx.h" 6: #include <math.h> 7: #include "Tasking.h" 8: #include "Spinner.h"</PRE><H2><A NAME="Heading8"></A>Supporting the Spinners</H2><P>Now that you've created the spinner class for drawing the spinning color wheelon the window, add some support for the spinners. You can add an array to hold thefour spinners in the document class, but you'll still need to calculate where eachspinner should be placed on the application window and set all the variables in eachof the spinners.</P><P>You can add all of this code to the document class, starting with the array ofspinners. Add a member variable to the document class (in this instance, CTaskingDoc),specifying the type as CSpinner, the name as m_cSpin[4], and the access as private.Once you add the array, open the source code to the document class and include thespinner header file, as in Listing 18.6.</P><P><H4>LISTING 18.6. THE CTaskingDoc SOURCE FILE.</H4><PRE> 1: // TaskingDoc.cpp : implementation of the CTaskingDoc class 2: // 3: 4: #include "stdafx.h" 5: #include "Tasking.h" 6: 7: #include "Spinner.h" 8: #include "TaskingDoc.h" 9: #include "TaskingView.h"10: .11: .12: . </PRE><H4>Calculating the Spinner Positions</H4><P>One of the preparatory things that needs to happen while initializing the applicationis determining the locations of all four spinners. The window is roughly broken upinto four quarters by the check boxes that will turn the spinner threads on and off,so it makes sense to divide the window area into four quarter squares and place onespinner in each quarter.</P><P>To calculate the location of each spinner, it is easiest to create a functionthat calculates the location for one spinner, placing the spinner into the quartersquare appropriate for the spinner number. If the function was passed a pointer tothe spinner object, it could update the spinner object directly with the location.</P><P>To add this functionality to your application, add a new member function to thedocument class (for instance, in the CTaskingDoc class). Specify the function typeas void, the declaration as CalcPoint(int nID, CSpinner *pSpin), and the access asprivate. Edit the function, adding the code in Listing 18.7.</P><P><H4>LISTING 18.7. THE CTaskingDoc CalcPoint FUNCTION.</H4><PRE> 1: void CTaskingDoc::CalcPoint(int nID, CSpinner *pSpin) 2: { 3: RECT lWndRect; 4: CPoint pPos; 5: int iLength; 6: CTaskingView *pWnd; 7: 8: // Get a pointer to the view window 9: pWnd = (CTaskingView*)pSpin->GetViewWnd();10: // Get the display area rectangle11: pWnd->GetClientRect(&lWndRect);12: // Calculate the size of the spinners13: iLength = lWndRect.right / 6;14: // Which spinner are we placing?15: switch (nID)16: {17: case 0: // Position the first spinner18: pPos.x = (lWndRect.right / 4) - iLength;19: pPos.y = (lWndRect.bottom / 4) - iLength;20: break;21: case 1: // Position the second spinner22: pPos.x = ((lWndRect.right / 4) * 3) - iLength;23: pPos.y = (lWndRect.bottom / 4) - iLength;24: break;25: case 2: // Position the third spinner26: pPos.x = (lWndRect.right / 4) - iLength;27: pPos.y = ((lWndRect.bottom / 4) * 3) - (iLength * 1.25);28: break;29: case 3: // Position the fourth spinner30: pPos.x = ((lWndRect.right / 4) * 3) - iLength;31: pPos.y = ((lWndRect.bottom / 4) * 3) - (iLength * 1.25);32: break;33: }34: // Set the size of the spinner35: pSpin->SetLength(iLength);36: // Set the location of the spinner37: pSpin->SetPoint(pPos);38: }</PRE><P>In this function, the first thing that you do is move the pointer to the viewwindow from the spinner object by calling the GetViewWnd function:</P><P><PRE>pWnd = (CTaskingView*)pSpin->GetViewWnd();</PRE><P>By moving the pointer directly from the spinner object, you save a few steps bytaking a more direct route to get the information that you need.</P><P>Once you have a pointer to the view object, you can call the window's GetClientRectfunction to get the size of the available drawing area:</P><P><PRE>pWnd->GetClientRect(&lWndRect);</PRE><P>Once you have the size of the drawing area, you can calculate a reasonable colorwheel size by dividing the length of the drawing area by 6:</P><P><PRE>iLength = lWndRect.right / 6;</PRE><P>Dividing the drawing area by 4 will position you at the middle of the upper-leftsquare. Subtract the size of the circle from this point, and you have the upper-leftcorner of the drawing area for the first spinner:</P><P><PRE>pPos.x = (lWndRect.right / 4) - iLength;</PRE><PRE>pPos.y = (lWndRect.bottom / 4) - iLength;</PRE><P>You can then include variations on this position, mostly by multiplying the centerof the quadrant by 3 to move it to the center of the right or lower quadrant, andyou can calculate the positions of the other three spinners.</P><P>Once you calculate the length and position for the spinner, you call the SetLengthand SetPoint functions to pass these values to the spinner that they have been calculatedfor:</P><P><PRE>pSpin->SetLength(iLength);pSpin->SetPoint(pPos);</PRE><H4>Initializing the Spinners</H4><P>Because you wrote the previous function to calculate the location of each spinneron the window to work on only one spinner each time it is called, you need some routinethat will initialize each spinner, calling the previous function once for each spinner.You need this function to get a pointer to the view object and pass that along tothe spinner. You also need to get pointers to the check box variables for the spinnersthat will be used by the independently running threads. Your code can do all thisby just looping through the array of spinners, setting both of these pointers foreach spinner, and then passing the spinner to the function you just finished.</P><P>To create this function for your application, add a new member function to thedocument class (CTaskingDoc in this instance). Specify the type as void, and givethe function a suitable name (for instance, InitSpinners), and then specify the accessas private because you'll only need to call this function once when the applicationis starting. Edit the new function, adding the code in Listing 18.8.</P><P><H4>LISTING 18.8. THE CTaskingDoc InitSpinners FUNCTION.</H4><PRE> 1: void CTaskingDoc::InitSpinners()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -