版权声明:本文为博主原创文章,转载注明出处。 https://blog.csdn.net/pengjc2001/article/details/56268144
看完第5章,突然想写一个类cad的程序,先做简单功能描述及可能用到的函数
1、画直线,线宽、线形可以设置,鼠标左键开始绘图,鼠标移动时,跟踪鼠标绘制直线,再次左键,直线绘制完毕,同时开始绘制下一直线,右键结束直线绘制。线形线宽在开始绘图时设置。
2、鼠标滚动,放大 缩小, 放大的中心区为鼠标位置。
问题1的解决过程,有意思的地方是,直线的末端跟随鼠标调整直线的位置。在这鼠标移动的事件中,不停的绘制 起点 到 终点(当前鼠标坐标)的直线,
a、那么问题来了,鼠标前一位置画出的直线怎么办? 解决之道, 要么处理当前 WM_MOUSEMOVE 消息时, 用背景色绘制 前面一条直线(相当于把前面那条直线擦除),再绘制当前直线。
b、问题又来了,如果前一条直线与已绘制的直线有交点时, 那么擦除前一条直线时,同时把已绘制的直线上的那个交点也擦除了。这种状态在windows绘图软件中也是存在的。后画上的直线会把前面的直线覆盖掉。
如果要解决上面的问题,目前能想到的解决方案是,把图形的绘制丢给WM_PAINT,它的每次更新都是当前图像的最新状态。 但是问题又来了,随着图元的增加,WM_PAINT会越来越慢。
在对问题2的探索过程中,发现如果真的要实现类cad功能的话,得放弃GDI了 转向矢量图寻找解决方案。
1、记录当前鼠标点坐标,
2、放大后点坐标 = 相对坐标X放大系数 + 鼠标当前坐标。
注意:
滚轮的滚动使Windows产生的WM_MOUSEWHEEL消息,参数lParam包含鼠标的位置信息,但是,这些坐标是相对于屏幕左上角的坐标,而不是客户区的坐标。
所以,程序里使用的坐标是有WM_MOUSEMOVE消息中得到的。
#include <windows.h>
#include <windowsx.h>
#include <vector>
using std::vector;
vector<POINT> pt;
enum LineStyle {HeavyLine, LightLine, DashLine};
struct line
{
POINT ptStart;
POINT ptEnd;
enum LineStyle lineStyel;
};
vector<line> lines;
vector<line> lines_scaled;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DrawLines") ;
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 ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Connect-the-Points Mouse Demo"),
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 iCount =0;
static int cxClient, cyClient;
static float scaleratio = 1;
static HPEN hPen[3];
line lineTmp;
HDC hdc ;
PAINTSTRUCT ps ;
static POINT aptStart = {0,0}, aptEnd = { 0,0 }, aptCurrent;
static BOOL fdraw = 0;
switch (message)
{
case WM_CREATE:
hPen[0] = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
hPen[1] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
hPen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_LBUTTONDOWN:
aptEnd.x = GET_X_LPARAM(lParam);
aptEnd.y = GET_Y_LPARAM(lParam);
if (fdraw != 0)
{
lineTmp.ptStart = aptStart;
lineTmp.ptEnd = aptEnd;
lineTmp.lineStyel = HeavyLine;
lines.push_back(lineTmp);
iCount++;
}
aptStart = aptEnd;
fdraw = 1;
InvalidateRect(hwnd, NULL, TRUE);
return 0 ;
case WM_RBUTTONDOWN:
fdraw = 0;
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_MOUSEMOVE:
if (fdraw)
{
aptEnd.x = GET_X_LPARAM(lParam);
aptEnd.y = GET_Y_LPARAM(lParam);
InvalidateRect(hwnd,NULL,TRUE);
}
aptCurrent.x= GET_X_LPARAM(lParam);
aptCurrent.y = GET_Y_LPARAM(lParam);
return 0 ;
case WM_MOUSEWHEEL:
if (!lines_scaled.empty())
{
if ((short)HIWORD(wParam)>0)
{
scaleratio = 1.25;
}
else
{
scaleratio = 0.8;
}
for (int i = 0;i < (int)lines_scaled.size();i++)
{
lines_scaled[i].ptStart.x = scaleratio*(lines_scaled[i].ptStart.x - aptCurrent.x) + aptCurrent.x;
lines_scaled[i].ptStart.y = scaleratio*(lines_scaled[i].ptStart.y - aptCurrent.y) + aptCurrent.y;
lines_scaled[i].ptEnd.x = scaleratio*(lines_scaled[i].ptEnd.x - aptCurrent.x) + aptCurrent.x;
lines_scaled[i].ptEnd.y = scaleratio*(lines_scaled[i].ptEnd.y - aptCurrent.y) + aptCurrent.y;
}
hdc = GetDC(hwnd);
Rectangle(hdc,0,0, cxClient, cyClient);
for (int i = 0; i < (int)lines_scaled.size(); i++)
{
MoveToEx(hdc, lines_scaled[i].ptStart.x, lines_scaled[i].ptStart.y, NULL);
LineTo(hdc, lines_scaled[i].ptEnd.x, lines_scaled[i].ptEnd.y);
}
ReleaseDC(hwnd, hdc);
}
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
ShowCursor (TRUE) ;
if (iCount == 0 && fdraw)
{
SetPixel(hdc, aptStart.x, aptStart.y, 0);
MoveToEx(hdc, aptStart.x, aptStart.y, NULL);
LineTo(hdc, aptEnd.x, aptEnd.y);
}
else if (iCount != 0 && !fdraw)
{
for (int i = 0; i < iCount; i++)
{
MoveToEx(hdc, lines[i].ptStart.x, lines[i].ptStart.y, NULL);
LineTo(hdc, lines[i].ptEnd.x, lines[i].ptEnd.y);
}
}
else if (iCount != 0 && fdraw)
{
for (int i = 0; i < iCount; i++)
{
MoveToEx(hdc, lines[i].ptStart.x, lines[i].ptStart.y, NULL);
LineTo(hdc, lines[i].ptEnd.x, lines[i].ptEnd.y);
}
MoveToEx(hdc, aptStart.x, aptStart.y, NULL);
LineTo(hdc, aptEnd.x, aptEnd.y);
}
ShowCursor (FALSE) ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
EndPaint (hwnd, &ps) ;
if (!lines_scaled.empty())
lines_scaled.clear();
lines_scaled = lines;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
DeleteObject(hPen[0]);
DeleteObject(hPen[1]);
DeleteObject(hPen[2]);
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}