相对于用自己画矩形来画橡皮擦矩形,效率比较低的,所以使用矩形画图函数来实现。然而经过测试,其实性能提升还是不够。我们会发现,当鼠标快速滑过之后,矩形还是不连续哦。虽然说对于橡皮擦功能来说,不连续影响不大,但是能够连续是最好了。然而现实很残酷,要实现连续的橡皮擦,也就只能借鉴划线的方法。其实就是将橡皮擦当做划线一样来处理,只是设置的颜色必须是背景颜色,才有橡皮擦的性质。既然如此,能够提高,那就这样实现了。
在用这个方法之前,我仔细研究了PS的实现,当快速移动之后,不能实时跟进,虽然缓慢的但是还是能够完成比较满意的连续擦除线的。而用擦除背景方式,将橡皮擦范围设置大,然后就出现比较明显的圆形。PS擦除前景的话就很难看到明显的圆形边界。PS的橡皮擦处理效果如下:
PS擦除背景出现明显的圆形轮廓
PS擦除前景轮廓明显很少了
在这个调查下,我用直接划线的方式,将线条大小设置的很大,用来擦除,就和PS擦除前景一样的效果,而且不会断续,其实就是和划线一个,只是逻辑上将它当做了橡皮擦了。而且实现就和画图的实现是一样的。用直线画图的请参考本文前面提到的文章“自由绘图的功能标准实现”。而使用矩形或圆形填充方式来擦除背景的,则始终不能完美达到不断线的擦除。鼠标移动快了就会出现断开的地方没有被擦除。PS也是没有完全实现,只不过优化的很好了,我们就不继续追下去了。如果你有兴趣,可以继续优化实现哦。我们可以看看出现处理的效果:
以背景色画直线方式来擦除的效果
用填充矩形的方式擦除的效果,快速移动不连续
用填充圆形的方式擦除的效果,快速移动不连续
#include "windows.h"
#include <Windowsx.h>//GET_X_LPARAM,GET_Y_LPARAM宏需要这个头文件
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static bool bisPaint=false;
static bool bisClear=false;
static bool bisMove=false;
TCHAR Info[100]=_T("【C++技术网http://www.cjjjs.com】");
static POINT ptOld;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);//会清除无效矩形
TextOut(hdc,0,10,Info,lstrlen(Info));
EndPaint(hwnd,&ps);
return 0;
case WM_LBUTTONDOWN:
bisPaint=true;//开始作画
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
return 0;
case WM_LBUTTONUP:
bisPaint=false;//松开鼠标,结束绘画
return 0;
case WM_RBUTTONDOWN:
bisClear=true;
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
bisMove=true;
return 0;
case WM_RBUTTONUP:
bisClear=false;
bisMove=false;
return 0;
case WM_KEYDOWN:
InvalidateRect(hwnd,NULL,TRUE);
return 0;
case WM_MOUSEMOVE:
if(bisClear)
{
//-擦除绘图
hdc = GetDC(hwnd);
if(bisMove)
{
MoveToEx(hdc,ptOld.x,ptOld.y,NULL);//设置bisMove只需要第一次设置,后面的不需要再设置了
}
SelectObject(hdc,CreatePen(PS_SOLID,50,RGB(0,0,0)));
DeleteObject(GetStockObject(BLACK_PEN));//自己创建的画笔要删除
LineTo(hdc,ptOld.x=GET_X_LPARAM(lParam),ptOld.y=GET_Y_LPARAM(lParam));
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
////-用圆形矩形区域填充来实现橡皮擦,提高效率
//SelectObject(hdc,GetStockObject(BLACK_BRUSH));
//int size=20;
////橡皮擦
//Rectangle(hdc,GET_X_LPARAM(lParam)-size,GET_Y_LPARAM(lParam)-size,GET_X_LPARAM(lParam)+size,GET_Y_LPARAM(lParam)+size);
//Ellipse(hdc,GET_X_LPARAM(lParam)-size,GET_Y_LPARAM(lParam)-size,GET_X_LPARAM(lParam)+size,GET_Y_LPARAM(lParam)+size);
ReleaseDC(hwnd,hdc);
}else if(bisPaint)//如果按着鼠标时,表示在作画,因此可以开始绘制
{
hdc = GetDC(hwnd);
MoveToEx(hdc,ptOld.x,ptOld.y,NULL);
SelectObject(hdc,CreatePen(PS_SOLID,50,RGB(255,0,0)));
LineTo(hdc,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
ptOld.x = GET_X_LPARAM(lParam);
ptOld.y = GET_Y_LPARAM(lParam);
ReleaseDC(hwnd,hdc);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
TCHAR ClassName[] = _T("MyClass");
TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
WNDCLASS wndClass;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WinProc;
wndClass.lpszClassName = ClassName;
wndClass.lpszMenuName=NULL;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndClass))return 0;
HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}