Saturday, November 5, 2011

Freehand Drawing, the Paintbrush Style of .Graphics Under Windows in C programming

Even if you are knee high in computers I am sure you must have used PaintBrush. It provides a facility to draw a freehand drawing using mouse. Let us see if we too can achieve this. We can indicate where the freehand drawing begins by clicking the left mouse button. Then as we move the mouse on the table with the left mouse button depressed the freehand drawing should get drawn in the window. This drawing should continue till we do not release the left mouse button.
The mouse input comes in the form of messages. For free hand drawing we need to tackle three mouse messages— WM_LBUTTONDOWN for left button click, WM_MOUSEMOVE for mouse movement and WM_LBUTTONUP for releasing the left mouse button. Let us now see how these messages are tackled for drawing freehand. The 
WndProc( ) function and the message handlers that perform this task are given below
int x1, y1, x2, y2 ;
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY :
OnDestroy ( hWnd ) ;
break ;
case WM_LBUTTONDOWN :
OnLButtonDown ( hWnd, LOWORD ( lParam ),
HIWORD ( lParam ) ) ;
break ;
case WM_LBUTTONUP :
OnLButtonUp( ) ;
break ;
case WM_MOUSEMOVE :
OnMouseMove ( hWnd, wParam, LOWORD ( lParam ), HIWORD ( lParam ) ) ;
break ;
default:
return DefWindowProc ( hWnd, message, wParam, lParam ) ;
}
return 0 ;
}
void OnLButtonDown ( HWND hWnd, int x, int y )
{
SetCapture ( hWnd ) ;
x1 = x ;
y1 = y ;
}
void OnMouseMove ( HWND hWnd, int flags, int x, int y )
{
HDC hdc ;
if ( flags == MK_LBUTTON ) /* is left mouse button depressed */
{
hdc = GetDC ( hWnd ) ;
x2 = x ;
y2 = y ;
MoveToEx ( hdc, x1, y1, NULL ) ;
LineTo ( hdc, x2, y2 ) ;
ReleaseDC ( hWnd, hdc ) ;
x1 = x2 ;
y1 = y2 ;
}
}
void OnLButtonUp( )
{
ReleaseCapture( ) ;
}
On execution of this program the window shown in Figure 18.5 appears. We can now click the left mouse button with mouse pointer placed anywhere in the window. We can then drag the mouse on the table to draw the freehand. The freehand drawing would continue till we do not release the left mouse button.








It appears that for drawing the freehand we should simply receive the mouse coordinates as it is moved and then highlight the pixels at these coordinates using the SetPixel( ) API function. However, if we do so the freehand would be broken at several places. This is because usually the mouse is dragged pretty fast whereas the mouse move messages won’t arrive so fast. A solution to this problem is to construct the freehand using small little line segments. This is what has been done in our program. These lines are so small is size that you would not even recognize that the freehand has been drawn by connecting these small lines.
Let us now discuss each mouse handler. When the WM_LBUTTONDOWN message arrives the WndProc( ) function calls the handler OnLButtonDown( ). While doing so, we have passed the mouse coordinates where the click occurred. These coordinates are obtained in lParam in WndProc( ). In lParam the low order 16 bits contain the current x - coordinate of the mouse whereas the high order 16 bits contain the y - coordinate. The LOWORD and HIWORD macros have been used to separate out these x and y - coordinates from lParam.
In OnLButtonDown( ) we have preserved the starting point of freehand in global variables x1 and y1.
When OnMouseMove( ) gets called it checks whether the left mouse button stands depressed. If it stands depressed then the flags variable contains MK_LBUTTON. If it does, then the current mouse coordinates are set up in the global variables x2, y2. A line is then drawn between x1, y1 and x2, y2 using the functions MoveToEx( ) and LineTo( ). Next time around x2, y2 should become the starting of the next line. Hence the current values of x2, y2 are stored in x1, y1.
Note that here we have obtained the DC handle using the API function GetDC( ). This is because we are carrying out the drawing activity in reaction to a message other than WM_PAINT. Also, the handle obtained using GetDC( ) should be released using a call to ReleaseDC( ) function.
You can try using BeginPaint( ) / EndPaint( ) in mouse handlers and GetDC( ) / ReleaseDC( ) in OnPaint( ). Can you draw any conclusions?

No comments:

Post a Comment