Draw some lines

I'm starting to experiment with windows graphics, and I'm trying to make a program that will draw lines to the screen like a pen. (I will be expanding this program into something more like windows paint eventually, mostly for practice)
Right now I have it drawing lines to the screen using polyline(), but it connects the end of the first line with the start of the next line. My brain feels fried just with learning pointers to class objects, so I'm just lost as far as how to stop it from connecting the lines.


Any help or hints?

Source.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <windows.h>
#include <fstream>
#include <math.h>
#include "paintObj.h"

#define NUM    1000
#define TWOPI  (2 * 3.14159)


paintObj pt[1000];
paintObj* pnt = &pt[0]; 
int objcount = 0;//used to increment *pnt through pt[] in WM_paint
int painted = 0;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{

	static TCHAR szAppName[] = TEXT ("Painter") ;
	HWND         hwnd ;
	MSG          msg ;
	WNDCLASS     wndclass ;
	
	wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance     = hInstance ;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName  = NULL ;
	wndclass.lpszClassName = szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("Class failed registration"), 
		szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Paint a line"),
	WS_OVERLAPPEDWINDOW,
	CW_USEDEFAULT, CW_USEDEFAULT,
	CW_USEDEFAULT, CW_USEDEFAULT,
	NULL, NULL, hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int  cxClient, cyClient ;
	HDC         hdc ;
	PAINTSTRUCT ps ;
	RECT Clientarea;//used to invalidate client area to force re-paint
	
	switch (message)
	{
		case WM_LBUTTONDOWN:
		{	
			objcount++;
			pnt = &pt[objcount];
			
			cxClient = LOWORD (lParam) ;
			cyClient = HIWORD (lParam) ;
			pnt->polySet("start",cxClient, cyClient);
			
		}
		return 0;
		case WM_MOUSEMOVE:
		{
			if(wParam ==MK_LBUTTON)
			{
				cxClient = LOWORD (lParam) ;
				cyClient = HIWORD (lParam) ;
				pnt->polySet("next",cxClient, cyClient); 
			}
			GetClientRect(hwnd, &Clientarea);
			InvalidateRect(hwnd, &Clientarea,0);
		}
		
		return 0;
		
		case WM_SIZE:
		
		return 0 ;
		
		case WM_PAINT:
		
		hdc = BeginPaint (hwnd, &ps) ;
		
		painted = 0;
		while(painted <1000)
		{
			
			pnt = &pt[painted];
			painted ++;
			if(pnt->cnt <1000)
			{
				Polyline(hdc, pnt->Pols, pnt->cnt) ;
			}
		}
		EndPaint(hwnd, &ps);
		
		
		return 0 ;
		
		case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}



paintObj.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once
#include <Windows.h>
#include <string>
#include <vector>

using namespace std;

class paintObj
{
	public:
	paintObj();
	int polySet(string, int x, int y);//use to finish initializing a poly line, use elipse to get full list of points
	int polyPoint();//
	void modPoint(POINT &, int, int);
	void modRect(RECT &, int, int);
	~paintObj(void);
	POINT Pols[1000];//made public for easier access
	int cnt;
	private:
	
	int set;
	RECT paintR;
	
};



paintObj.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "paintObj.h"

paintObj::paintObj()
{
	paintR;		
	
}
int paintObj::polySet(string desc,int x, int y)//use to finish initializing a poly line,
{
	if(desc == "start")
	{
		Pols[0].x = x;
		Pols[0].y = y;
		cnt = 0;
	}
	else if(desc == "next")
	{
		cnt++;
		Pols[cnt].x = x;
		Pols[cnt].y = y;
		return cnt;
	}
	
	
}

paintObj::~paintObj(void)
{
}
Last edited on
Use MoveToEx() and LineTo() instead.
If you want to draw multiple line segments with a single GDI call, then check out PolyPolyline and PolyDraw. Both give you the ability to draw multiple segments, unlike Polyline. As you know, this draws just a single "polyline" (ie a sequence of connected points).

PolyPolyline allows you to group the points, e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    case WM_PAINT:
    {
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd, &ps);

        const POINT aPoints[] =
        { {100, 100} // first polyline (5 points)
        , {100, 200}
        , {200, 200}
        , {200, 100}
        , {100, 100}
        , {120, 150} // second polyline (2 points)
        , {180, 150}
        , {150, 120} // third polyline (2 points)
        , {150, 180}
        };
 
        const DWORD adwPolyPoints[] = {5, 2, 2};

        const DWORD cCount = _countof(adwPolyPoints);

        PolyPolyline(
            hdc,
            aPoints,
            adwPolyPoints,
            cCount );

        EndPaint(hWnd, &ps);
    }
    break;


PolyDraw allows you to specify whether you move to a point or draw a line to it (also supports B├ęzier curves and automatic closing: see MSDN)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    case WM_PAINT:
    {
        PAINTSTRUCT ps = {0};
        HDC hdc = BeginPaint(hWnd, &ps);

        const POINT aPoints[] =
        { {400, 400} // first polyline (5 points)
        , {400, 500} // so need moveto, lineto, lineto, lineto, lineto
        , {500, 500}
        , {500, 400}
        , {400, 400}
        , {420, 450} // second polyline (2 points)
        , {480, 450} // so need moveto, lineto
        , {450, 420} // third polyline (2 points)
        , {450, 480} // so need moveto, lineto
        };

        const DWORD cCount = _countof(aPoints);
        
        const BYTE abTypes[] =
        { PT_MOVETO
        , PT_LINETO
        , PT_LINETO
        , PT_LINETO
        , PT_LINETO
        , PT_MOVETO
        , PT_LINETO
        , PT_MOVETO
        , PT_LINETO
        };

        PolyDraw(
            hdc,
            aPoints,
            abTypes,
            cCount );

        EndPaint(hWnd, &ps);
    }
    break;


Also, rather that making paintObj's POINT array "public for easier access", you could tighten up enapsulation by implenting a Draw(HDC hdc) (or whatever) method which gets the paintObj to draw itself??

Andy

PolyPolyline function (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162819%28v=vs.85%29.aspx

PolyDraw function (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162813%28v=vs.85%29.aspx
Last edited on
I figured out what my problem was. It had to do with overwriting Information in pnt, so I made pnt into an array as well and reserved one version of pnt for use in paint. I'll continue tinkering on this code, so thanks for the suggestions, I'll have to look-up those functions.
Topic archived. No new replies allowed.