GDI Fundamental Shapes |
|
|
|
Practical Learning: Introducing GDI Shapes |
|
Lines |
A line is a junction of two points. This means that a line has a beginning and an end: The beginning and the end are two distinct points . In real life, before drawing, you should define where you would start. To help with this, you can use MoveToEx() function. Its syntax is: BOOL MoveToEx(HDC hdc, int X, int Y, LPPOINT lpPoint); The origin of a drawing is specified as the (X, Y) point. To end the line, you use the LineTo() function. Its syntax is: BOOL LineTo(HDC hdc, int nXEnd, int nYEnd); The end of a line can be defined by its horizontal (nXEnd) and its vertical measures (nYEnd). Here is an example that draws a line starting at a point defined as (10, 22) coordinates and ending at (155, 64):
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); MoveToEx(hDC, 60, 20, NULL); LineTo(hDC, 264, 122); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
We have mentioned that the MoveToEx() function is used to set the starting position of a line. When using LineTo(), the line would start from the MoveToEx() point to the LineTo() end. As long as you do not call MoveToEx(), any subsequent call to LineTo() would draw a line from the previous LineTo() to the new LineTo() point. You can use this property of the LineTo() function to draw various lines. Here is an example:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); MoveToEx(hDC, 60, 20, NULL); LineTo(hDC, 60, 122); LineTo(hDC, 264, 122); LineTo(hDC, 60, 20); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
Practical Learning: Drawing a Line |
|
Polylines |
A polyline is a series of connected lines. The lines are stored in an array of POINT values. To draw a polyline, you can use the Polyline() function. Its syntax is: BOOL Polyline(HDC hdc, CONST POINT *lppt, int cPoints); The lppt argument is an array of points that can be of POINT types. The cPoints argument specifies the number of members of the array. When executing, the compiler moves the starting point to lppt[0]. The first line is drawn from lppt[0] to lppt[1] as in:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; POINT Pt[] = { 60, 20, 60, 122 }; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); MoveToEx(hDC, Pt[0].x, Pt[0].y, NULL); LineTo(hDC, Pt[1].x, Pt[1].y); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
To draw a polyline, you must have at least two points. If you define more than two points, each line after the first would be drawn from the previous point to the next point until all points have been included. Here is an example:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; POINT Pt[7]; Pt[0].x = 20; Pt[0].y = 50; Pt[1].x = 180; Pt[1].y = 50; Pt[2].x = 180; Pt[2].y = 20; Pt[3].x = 230; Pt[3].y = 70; Pt[4].x = 180; Pt[4].y = 120; Pt[5].x = 180; Pt[5].y = 90; Pt[6].x = 20; Pt[6].y = 90; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); Polyline(hDC, Pt, 7); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
Besides the Polyline() function, you can use the PolylineTo() function to draw a polyline. Its syntax is: BOOL PolylineTo(HDC hdc, CONST POINT *lppt, DWORD cCount); The lppt argument is the name of an array of POINT objects. The cCount argument specifies the number of points that would be included in the figure. Here is an example:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; POINT Pt[7]; Pt[0].x = 20; Pt[0].y = 50; Pt[1].x = 180; Pt[1].y = 50; Pt[2].x = 180; Pt[2].y = 20; Pt[3].x = 230; Pt[3].y = 70; Pt[4].x = 180; Pt[4].y = 120; Pt[5].x = 180; Pt[5].y = 90; Pt[6].x = 20; Pt[6].y = 90; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); PolylineTo(hDC, Pt, 7); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
While the Polyline() function starts the first line at lppt[0], the PolylineTo() member function does not control the beginning of the first line. Like the LineTo() function, it simply starts drawing, which would mean it starts at the origin (0, 0). For this reason, if you want to control the starting point of the PolylineTo() drawing, you can use the MoveToEx() function:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; POINT Pt[7]; Pt[0].x = 20; Pt[0].y = 50; Pt[1].x = 180; Pt[1].y = 50; Pt[2].x = 180; Pt[2].y = 20; Pt[3].x = 230; Pt[3].y = 70; Pt[4].x = 180; Pt[4].y = 120; Pt[5].x = 180; Pt[5].y = 90; Pt[6].x = 20; Pt[6].y = 90; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); MoveToEx(hDC, 20, 30, NULL); PolylineTo(hDC, Pt, 7); LineTo(hDC, 20, 110); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
Practical Learning: Drawing a Polyline |
. . . No Change //--------------------------------------------------------------------------- LRESULT CALLBACK MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; static BOOL IsDrawing = FALSE; static int StartX, StartY; static int EndX, EndY; switch(Msg) { case WM_CREATE: Exo.CreateStandardToolbar(hWnd, Exo.hInst); SendMessage(Exo.hWndToolbar, TB_SETSTATE, IDM_DRAW_ARROW, TBSTATE_CHECKED | TBSTATE_ENABLED); return 0; case WM_ACTIVATE: Exo.Wnd.SetText("RainDrop - Untitled"); return 0; case WM_LBUTTONDOWN: hDC = GetDC(hWnd); StartX = LOWORD(lParam); StartY = HIWORD(lParam); EndX = LOWORD(lParam); EndY = HIWORD(lParam); // If the Line button is down, draw with it if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_LINE, 0) & TBSTATE_CHECKED ) { SetROP2(hDC, R2_XORPEN); MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); } else if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_FREEHAND, 0) & TBSTATE_CHECKED ) { StartX = LOWORD(lParam); StartY = HIWORD(lParam); } else if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_POLYLINE, 0) & TBSTATE_CHECKED ) { SetROP2(hDC, R2_XORPEN); MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); } IsDrawing = TRUE; ReleaseDC(hWnd, hDC); return 0; case WM_MOUSEMOVE: hDC = GetDC(hWnd); if( IsDrawing == TRUE ) { SetROP2(hDC, R2_NOTXORPEN); // Find out if the Line button is clicked if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_LINE, 0) & TBSTATE_CHECKED ) { MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); EndX = LOWORD(lParam); EndY = HIWORD(lParam); MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); } // Find out if the Polyline button is clicked else if(SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_FREEHAND, 0) & TBSTATE_CHECKED ) { MoveToEx(hDC, EndX, EndY, NULL); EndX = LOWORD(lParam); EndY = HIWORD(lParam); LineTo(hDC, EndX, EndY); } else if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_POLYLINE, 0) & TBSTATE_CHECKED ) { MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); EndX = LOWORD(lParam); EndY = HIWORD(lParam); MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); } } ReleaseDC(hWnd, hDC); break; case WM_LBUTTONUP: hDC = GetDC(hWnd); EndX = LOWORD(lParam); EndY = HIWORD(lParam); SetROP2(hDC, R2_XORPEN); MoveToEx(hDC, StartX, StartY, NULL); LineTo(hDC, EndX, EndY); if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_LINE, 0) & TBSTATE_CHECKED ) { IsDrawing = FALSE; } if(SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_FREEHAND, 0) & TBSTATE_CHECKED ) { IsDrawing = FALSE; } ReleaseDC(hWnd, hDC); break; case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: // If the user press Esc, may be he/she was drawing a polyline // In that case, stop drawing IsDrawing = FALSE; break; default: break; } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_FILE_NEW: break; case IDM_FILE_OPEN: break; case IDM_FILE_SAVE: break; case IDM_FILE_SAVEAS: break; case IDM_FILE_EXIT: PostQuitMessage(WM_QUIT); break; case IDM_DRAW_ARROW: SendMessage(Exo.hWndToolbar, TB_SETSTATE, IDM_DRAW_ARROW, TBSTATE_CHECKED | TBSTATE_ENABLED); Exo.ChangeCurrentCursor(hWnd, IDC_ARROW); break; case IDM_DRAW_FREEHAND: SendMessage(Exo.hWndToolbar, TB_SETSTATE, IDM_DRAW_FREEHAND, TBSTATE_CHECKED | TBSTATE_ENABLED); Exo.ChangeCurrentCursor(hWnd, MAKEINTRESOURCE(IDC_FREEHAND)); break; case IDM_DRAW_LINE: SendMessage(Exo.hWndToolbar, TB_SETSTATE, IDM_DRAW_LINE, TBSTATE_CHECKED | TBSTATE_ENABLED); Exo.ChangeCurrentCursor(hWnd, MAKEINTRESOURCE(IDC_LINE)); break; case IDM_DRAW_POLYLINE: SendMessage(Exo.hWndToolbar, TB_SETSTATE, IDM_DRAW_POLYLINE, TBSTATE_CHECKED | TBSTATE_ENABLED); Exo.ChangeCurrentCursor(hWnd, MAKEINTRESOURCE(IDC_POLYLINE)); break; } return 0; case WM_DESTROY: PostQuitMessage(WM_QUIT); return 0; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return TRUE; } //--------------------------------------------------------------------------- HWND Exercise::CreateStandardToolbar(HWND hParent, HINSTANCE hInst) { const int NUMBUTTONS = 9; TBBUTTON tbrButtons[NUMBUTTONS]; tbrButtons[0].iBitmap = 0; tbrButtons[0].idCommand = IDM_FILE_NEW; tbrButtons[0].fsState = TBSTATE_ENABLED; tbrButtons[0].fsStyle = TBSTYLE_BUTTON; tbrButtons[0].dwData = 0L; tbrButtons[0].iBitmap = 0; tbrButtons[0].iString = 0; tbrButtons[1].iBitmap = 1; tbrButtons[1].idCommand = IDM_FILE_OPEN; tbrButtons[1].fsState = TBSTATE_ENABLED; tbrButtons[1].fsStyle = TBSTYLE_BUTTON; tbrButtons[1].dwData = 0L; tbrButtons[1].iString = 0; tbrButtons[2].iBitmap = 2; tbrButtons[2].idCommand = IDM_FILE_SAVE; tbrButtons[2].fsState = TBSTATE_ENABLED; tbrButtons[2].fsStyle = TBSTYLE_BUTTON; tbrButtons[2].dwData = 0L; tbrButtons[2].iString = 0; tbrButtons[3].iBitmap = 3; tbrButtons[3].idCommand = IDM_FILE_PRINT; tbrButtons[3].fsState = TBSTATE_ENABLED; tbrButtons[3].fsStyle = TBSTYLE_BUTTON; tbrButtons[3].dwData = 0L; tbrButtons[3].iString = 0; tbrButtons[4].iBitmap = 0; tbrButtons[4].idCommand = 0; tbrButtons[4].fsState = TBSTATE_ENABLED; tbrButtons[4].fsStyle = TBSTYLE_SEP; tbrButtons[4].dwData = 0L; tbrButtons[4].iString = 0; tbrButtons[5].iBitmap = 4; tbrButtons[5].idCommand = IDM_DRAW_ARROW; tbrButtons[5].fsState = TBSTATE_ENABLED; tbrButtons[5].fsStyle = TBSTYLE_BUTTON | TBSTYLE_GROUP | TBSTYLE_CHECK; tbrButtons[5].dwData = 0L; tbrButtons[5].iString = 0; tbrButtons[6].iBitmap = 5; tbrButtons[6].idCommand = IDM_DRAW_FREEHAND; tbrButtons[6].fsState = TBSTATE_ENABLED; tbrButtons[6].fsStyle = TBSTYLE_BUTTON | TBSTYLE_GROUP | TBSTYLE_CHECK; tbrButtons[6].dwData = 0L; tbrButtons[6].iString = 0; tbrButtons[7].iBitmap = 6; tbrButtons[7].idCommand = IDM_DRAW_LINE; tbrButtons[7].fsState = TBSTATE_ENABLED; tbrButtons[7].fsStyle = TBSTYLE_BUTTON | TBSTYLE_GROUP | TBSTYLE_CHECK; tbrButtons[7].dwData = 0L; tbrButtons[7].iString = 0; tbrButtons[8].iBitmap = 7; tbrButtons[8].idCommand = IDM_DRAW_POLYLINE; tbrButtons[8].fsState = TBSTATE_ENABLED; tbrButtons[8].fsStyle = TBSTYLE_BUTTON | TBSTYLE_GROUP | TBSTYLE_CHECK; tbrButtons[8].dwData = 0L; tbrButtons[8].iString = 0; hWndToolbar = CreateToolbarEx(hParent, WS_VISIBLE | WS_CHILD | WS_BORDER, IDB_STANDARD, NUMBUTTONS, hInst, IDB_STANDARD, tbrButtons, NUMBUTTONS, 16, 16, 16, 16, sizeof(TBBUTTON)); if( hWndToolbar ) return hWndToolbar; return NULL; } //--------------------------------------------------------------------------- |
Multiple Polylines |
The above polylines were used each as a single entity. That is, a polyline is a combination of lines. If you want to draw various polylines in one step, you can use the PolyPolyline() function. By definition, the PolyPolyline() function is used to draw a series of polylines. Its syntax is: BOOL PolyPolyline(HDC hdc, CONST POINT *lppt, CONST DWORD *lpdwPolyPoints, DWORD cCount); Like the above Polyline() function, the lppt argument is an array of POINT values. The PolyPolyline() function needs to know how many polylines you would be drawing. Each polyline will use the points of the lpdwPolyPoints value but when creating the array of points, the values must be incremental. This means that PolyPolyline() will not access their values at random. It will retrieve the first point, followed by the second, followed by the third, etc. Therefore, your first responsibility is to decide where one polyline starts and where it ends. The good news (of course depending on how you see it) is that a polyline does not start where the previous line ended. Each polyline has its own beginning and its own ending point. Unlike Polyline(), here, the cCount argument is actually the number of shapes you want to draw and not the number of points (remember that each polyline "knows" or controls its beginning and end). The lpdwPolyPoints argument is an array or positive integers. Each member of this array specifies the number of vertices (lines) that its corresponding polyline will have. For example, imagine you want to draw M, followed by L, followed by Z. The letter M has 4 lines but you need 5 points to draw it. The letter L has 2 lines and you need 3 points to draw it. The letter Z has 3 lines so 4 points are necessary to draw it. You can store this combination of lines in an array defined as { 5, 3, 4 }. Here is an example:
|
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT Ps; POINT Pt[15]; DWORD lpPts[] = { 4, 4, 7 }; // Left Triangle Pt[0].x = 50; Pt[0].y = 20; Pt[1].x = 20; Pt[1].y = 60; Pt[2].x = 80; Pt[2].y = 60; Pt[3].x = 50; Pt[3].y = 20; // Second Triangle Pt[4].x = 70; Pt[4].y = 20; Pt[5].x = 100; Pt[5].y = 60; Pt[6].x = 130; Pt[6].y = 20; Pt[7].x = 70; Pt[7].y = 20; // Hexagon Pt[8].x = 145; Pt[8].y = 20; Pt[9].x = 130; Pt[9].y = 40; Pt[10].x = 145; Pt[10].y = 60; Pt[11].x = 165; Pt[11].y = 60; Pt[12].x = 180; Pt[12].y = 40; Pt[13].x = 165; Pt[13].y = 20; Pt[14].x = 145; Pt[14].y = 20; switch(Msg) { case WM_PAINT: hDC = BeginPaint(hWnd, &Ps); PolyPolyline(hDC, Pt, lpPts, 3); EndPaint(hWnd, &Ps); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //--------------------------------------------------------------------------- |
|
||
Previous | Copyright © 2004-2010 FunctionX, Inc. | Next |
|