Home

GDI Fundamental Shapes

 

Line-Based Shapes

 

Introduction

As mentioned in the previous lesson, in order to display something in a graphical application, you must draw that thing. The result of your drawing can be called a shape if it displays a recognizable figure. Sometimes it will simply be referred to as a graphic. The fundamental and easier shapes you can draw are geometric and they are the lines, rectangles, ellipse, etc. Of course, there are more complicated or advanced shapes than that.

//---------------------------------------------------------------------------
#include <windows.h>

//---------------------------------------------------------------------------
HWND hWnd;
LPCTSTR ClsName = L"GDIFund";
LPCTSTR WindowCaption = L"GDI Fundamentals";
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    MSG         Msg;
    WNDCLASSEX  WndClsEx;

    WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    WndClsEx.lpfnWndProc   = WndProc;
    WndClsEx.cbClsExtra    = NULL;
    WndClsEx.cbWndExtra    = NULL;
    WndClsEx.hInstance     = hInstance;
    WndClsEx.hIcon         = LoadIcon(hInstance, IDI_APPLICATION);
    WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClsEx.lpszMenuName  = NULL;
    WndClsEx.lpszClassName = ClsName;
    WndClsEx.hIconSm       = LoadIcon(hInstance, IDI_APPLICATION);

    RegisterClassEx(&WndClsEx);

    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                          ClsName,
                          WindowCaption,
                          WS_OVERLAPPEDWINDOW,
                          100,
                          120,
                          640,
                          480,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while( GetMessage(&Msg, NULL, 0, 0) )
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return 0;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch(Msg)
    {
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
//---------------------------------------------------------------------------
 

 

Practical Learning Practical Learning: Introducing GDI Shapes

  1. Start your programming environment and create a Win32 project or application. If you are using Visual C++, create it as an empty project
  2. Save it in a new folder named RainDrop1
    If you are using C++ Builder 6 or Dev-C++, save the unit as Exercise and save the project as RainDrop1
    If you are using Visual C++ or C++BuilderX, create a new source file and name it Exercise
  3. Create or add a new icon. Design it as follows:
     
    32 x 32 16 x 16
  4. Set its ID to IDI_RAINDROP and save it as raindrop.ico
  5. Create or add a new cursor designed as follows:
     
  6. Set its hot spot just at the tip of the left line
     
  7. Save it as IDC_FREEHAND
  8. Create or add a new 16 x 96 bitmap and design it as follows:
     
  9. Set its ID to IDB_STANDARD and save it as standard.bmp
  10. Create a menu as follows:
     
    Caption ID Prompt
    &File
    &New\tCtrl+N IDM_FILE_NEW Creates a new document\nNew
    &Open...\tCtrl+O IDM_FILE_OPEN Opens an existing document\nOpen
    &Save\tCtrl+S IDM_FILE_SAVE Saves the active document\nSave
    Save &As... IDM_FILE_SAVEAS Custom saves the active document\nSave As
    -
    &Print...\tCtrl+P IDM_FILE_PRINT Prints the current document\nPrint
    -
    E&xit IDM_FILE_EXIT Closes the application\nExit
    &Draw
    &Arrow IDM_DRAW_ARROW No tool selected\nNo Tool
    &Free Hand IDM_DRAW_FREEHAND Draws with a free hand\nFree Hand
  11. The ID of the menu is IDR_MAIN_MENU
  12. Save the resource file as RainDrop2.rc and add it to your project (it is automatically done in Visual C++ .NET)
  13. Create a header file named WinApp.h and type the following in it:
     
    #pragma once
    #include <windows.h>
    
    //---------------------------------------------------------------------------
    class WApplication
    {
    public:
    	// This constructor will initialize the application
    	WApplication();
    	void Create(HINSTANCE hInst, char *ClasName,
    		     WNDPROC WndPrc, LPCTSTR MenuName = NULL);
    
    	// Class Registration
    	void Register();
    
    protected:
    	// Global variable that holds the application
    	WNDCLASSEX _WndClsEx;
    };
    //---------------------------------------------------------------------------
  14. Create a source file named WinApp.cpp and type the following in it:
     
    #include "WinApp.h"
    #include "resource.h"
    
    //---------------------------------------------------------------------------
    WApplication::WApplication()
    {
    }
    
    void WApplication::Create(HINSTANCE hInst, char *ClsName,
    			   WNDPROC WndPrc, LPCTSTR MenuName)
    {
    	// Initializing the application using the application member variable
    	_WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    	_WndClsEx.style         = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
    	_WndClsEx.lpfnWndProc   = WndPrc;
    	_WndClsEx.cbClsExtra    = 0;
    	_WndClsEx.cbWndExtra    = 0;
    	_WndClsEx.hInstance     = hInst;
    	_WndClsEx.hIcon         = static_cast<HICON>(LoadImage(hInst,
                                            MAKEINTRESOURCE(IDI_RAINDROP),
                                            IMAGE_ICON,
    					32,
                                            32,
    					LR_DEFAULTSIZE));
    	_WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    	_WndClsEx.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    	_WndClsEx.lpszMenuName  = MAKEINTRESOURCE(IDR_MAIN_MENU);
    	_WndClsEx.lpszClassName = ClsName;
    	_WndClsEx.hIconSm       = static_cast<HICON>(LoadImage(hInst,
                                            MAKEINTRESOURCE(IDI_RAINDROP),
                                            IMAGE_ICON,
    					16,
                                            16,
    					LR_DEFAULTSIZE));
    }
    //---------------------------------------------------------------------------
    void WApplication::Register()
    {
    	RegisterClassEx(&_WndClsEx);
    }
    //---------------------------------------------------------------------------
  15. Create a header file named MainWnd.h and type the following in it:
     
    #pragma once
    #include <windows.h>
    
    //---------------------------------------------------------------------------
    class WWindow
    {
    public:
    	// We will use a default constructor to declare a window
    	WWindow();
    	// The Create() method wil be used to initialize a window
    	HWND Create(HINSTANCE hinst,
    		    LPCTSTR clsname,
         		    LPCTSTR wndname,
    	            HWND parent   = NULL,
    	            DWORD dStyle  = WS_OVERLAPPEDWINDOW,
    	            DWORD dXStyle = 0L,
    		    int x         = CW_USEDEFAULT,
                        int y         = CW_USEDEFAULT,
    		    int width     = CW_USEDEFAULT,
                        int height    = CW_USEDEFAULT);
    
    	// This method will be used to display the window
    	BOOL Show(int dCmdShow = SW_SHOWNORMAL);
    
    	// Because each window is of type HWND, we will need a way
    	// to recognize the window handle when used in our application
    	operator HWND();
    
    // Accessories
    public:
    	void SetText(LPCTSTR strCaption);
    
    protected:
    	// This will be a global handle available to
    	// this and other windows
    	HWND _hwnd;
    };
    //---------------------------------------------------------------------------
  16. Create a source file named MainWnd.cpp and type the following in it:
     
    #include "MainWnd.h"
    
    //---------------------------------------------------------------------------
    WWindow::WWindow()
    {
    	// If we declare a window class with a default constructor,
    	// we need to reset the window to a nothing
    	_hwnd = NULL;
    }
    //---------------------------------------------------------------------------
    HWND WWindow::Create(HINSTANCE hinst,
        				 LPCTSTR clsname,
    	    			 LPCTSTR wndname,
    	  	    		 HWND parent,
    			    	 DWORD dStyle,
    					 DWORD dXStyle,
    				     int x,
         				 int y,
    	     			 int width,
    		    		 int height)
    {
    	// When call the Create() method, we can use it to create a new window
    	_hwnd = CreateWindowEx(dXStyle, clsname, wndname, dStyle, x, y, width,
    		                   height, parent, NULL, hinst, NULL);
    
    	// We hope everything went alright and the window was created
    	if( _hwnd != NULL )
    		return _hwnd;
    	// If something went wrong, for example if the window could not
    	// be created, return a "nothing" window
    	return NULL;
    }
    //---------------------------------------------------------------------------
    BOOL WWindow::Show(int dCmdShow)
    {
    	// We will display the main window as a regular object and update it
    	if(	ShowWindow(_hwnd, dCmdShow) && UpdateWindow(_hwnd) )
    		return TRUE;
    	return FALSE;
    }
    //---------------------------------------------------------------------------
    WWindow::operator HWND()
    {
    	// This overloaded operator allows us to use HWND anyway we want
    	return _hwnd;
    }
    //---------------------------------------------------------------------------
    void WWindow::SetText(LPCTSTR strCaption)
    {
    	SendMessage(_hwnd, WM_SETTEXT, 0, (LPARAM)strCaption);
    }
    //---------------------------------------------------------------------------
  17. Create a header file named Exercise.h and type the following in it:
     
    #pragma once
    
    #include "WinApp.h"
    #include "MainWnd.h"
    //---------------------------------------------------------------------------
    class Exercise
    {
    public:
    	Exercise();
    	WWindow Wnd;
    	HINSTANCE hInst;
    	WApplication WinApp;
    	HWND CreateStandardToolbar(HWND hParent, HINSTANCE hInst);
    	HWND hWndToolbar;
    
    public:
    	void ChangeCurrentCursor(HWND hWnd, LPCTSTR cursor);
    };
    //---------------------------------------------------------------------------
    LRESULT CALLBACK MainWndProc(HWND hWnd, UINT Msg,
                                 WPARAM wParam, LPARAM lParam);
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,
    				   LPSTR lpCmdLine, int nCmdShow);
    //---------------------------------------------------------------------------
  18. Open the Exercise.cpp source file and type the following in it:
     
    #include <windows.h>
    #include <commctrl.h>
    #include "resource.h"
    
    #include "Exercise.h"
    
    // This is for Visual C++
    #pragma comment(lib, "COMCTL32.lib")
    Exercise Exo;
    
    //---------------------------------------------------------------------------
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst,
    				   LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG   Msg;
    	LPCTSTR ClsName = L"Win32OOP";
    	LPCTSTR WndName = L"Object-Oriented Win32 Programming";
    
    	Exo.hInst = hInstance;
    
    	// Initialize the Common Controls
    	INITCOMMONCONTROLSEX InitCtrlEx;
    
    	InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
    	InitCtrlEx.dwICC  = ICC_BAR_CLASSES;
    	InitCommonControlsEx(&InitCtrlEx);
    
    	// Initialize the application class
    	Exo.WinApp.Create(Exo.hInst, ClsName, MainWndProc);
    	Exo.WinApp.Register();
    
    	// Create the main window
    	Exo.Wnd.Create(Exo.hInst, ClsName, WndName);
    	// Display the main winow
    	Exo.Wnd.Show();
    	
    	// Process the main window's messages
    	while( GetMessage(&Msg, NULL, 0, 0) )
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return 0;
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK MainWndProc(HWND hWnd, UINT Msg,
                                 WPARAM wParam, LPARAM lParam)
    {
    	
    	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_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;
    		};
    		return 0;
    
    	case WM_DESTROY:
    		PostQuitMessage(WM_QUIT);
    		return 0;
    
    	default:
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    
    	return TRUE;
    }
    //---------------------------------------------------------------------------
    Exercise::Exercise()
    {
    }
    //---------------------------------------------------------------------------
    HWND Exercise::CreateStandardToolbar(HWND hParent, HINSTANCE hInst)
    {
    	const int NUMBUTTONS = 7;
    	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;
    
    	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;
    }
    //---------------------------------------------------------------------------
    void Exercise::ChangeCurrentCursor(HWND hWnd, LPCTSTR cursor)
    {
    	HCURSOR crsCross;
    
    	crsCross = LoadCursor(hInst, cursor);
    	SetClassLong(hWnd, GCL_HCURSOR, (LONG)crsCross);
    }
    //---------------------------------------------------------------------------
  19. Execute the application
     
    RainDrop
  20. Close it and return to your programming environment

Lines

A line is a junction of two points. This means that a line has a beginning and an end:

Line

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 Practical Learning: Drawing a Line

  1. Under the Arrow menu item of the Draw category, add a new menu item IDentified as IDM_DRAW_LINE with a caption of &Line with a Prompt of Draws a straight line\nLine
  2. Add a new bitmap to the right of the IDB_STANDARD resource as follows:
     
  3. Save the bitmap
  4. Design a new cursor as follows:
     
  5. Set its hot spot to the intersection of the left cross
  6. Set its ID to IDC_LINE and save it as line.cur
  7. To be able to draw a line, change the Exercise.cpp source file as follows:
     
    //---------------------------------------------------------------------------
    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;
    	UINT iButtonState;
    
    	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:
    		// Find out if the Line button is clicked
    		iButtonState = SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_LINE, 0);
    
    		// If the Line button is down, draw with it
    		if( iButtonState & TBSTATE_CHECKED )
    		{
    			hDC = GetDC(hWnd);
    			StartX = LOWORD(lParam);
    			StartY = HIWORD(lParam);
    		
    			EndX = LOWORD(lParam);
    			EndY = HIWORD(lParam);
    		
    			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);
    		
    			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);
    
    		IsDrawing = FALSE;
    
    		ReleaseDC(hWnd, hDC);
    
    		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;
    		};
    		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 = 8;
    	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;
    
    	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;
    }
    //---------------------------------------------------------------------------
  8. Execute the application and test it
     
  9. Return to your programming environment
  10. To take care of the free hand drawing, change the main window procedure as follows:
     
    //---------------------------------------------------------------------------
    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);
    			IsDrawing = TRUE;
    		}
    		else if( SendMessage(Exo.hWndToolbar, TB_GETSTATE, IDM_DRAW_FREEHAND, 0) & TBSTATE_CHECKED )
    		{
    			StartX = LOWORD(lParam);
    			StartY = HIWORD(lParam);
    			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
    			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);
    			}
    		}
    		
    		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);
    
    		IsDrawing = FALSE;
    
    		ReleaseDC(hWnd, hDC);
    
    		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;
    		};
    		return 0;
    
    	case WM_DESTROY:
    		PostQuitMessage(WM_QUIT);
    		return 0;
    
    	default:
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    
    	return TRUE;
    }
    //---------------------------------------------------------------------------
  11. Test the application:
     
  12. Return to your programming environment

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;
}
//---------------------------------------------------------------------------
Polyline

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 Practical Learning: Drawing a Polyline

  1. Under the Arrow menu item of the Draw category, add a new menu item IDentified as IDM_DRAW_PLOYLINE with a caption of &Polyline with a Prompt of Draws a series of lines\nPolyline
  2. Add a new bitmap to the right of the IDB_STANDARD resource as follows:
     
  3. Save the bitmap
  4. Design a new cursor as follows:
     
  5. Set its hot spot to the intersection of the left diagonal lines
  6. Set its ID to IDC_POLYLINE and save it as polyline.cur
  7. To be able to draw a line, change the Exercise.cpp source file as follows:
     
     . . . 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;
    }
    //---------------------------------------------------------------------------
  8. Execute the application to test it
     
  9. Return to your programming environment

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