今天讲的是可以绘图过程中实时反色。这个效果用前面自己取色反色绘图也是可以实现的,但是如果这么做的话,效率跟不上,就出现滑动快了断线情况。而如果用画线方式解决断线问题,那么每一个点的就不能得到反色的效果了。因为一条直线经过的点,我们不会都去处理一遍,不然效率就和用SetPixel实现划线差不多了,甚至更差。对于SetPixel实现划线的实现分析,你可以参考《使用SetPixel在客户区自由绘画的功能实现》。
所以,实时绘图的发色效果还不断线,我们还是得用一个高效的方式,就是设置绘图方式,设置绘图方式的函数是SetROP2。因为这个实现是基于视频适配器级别的实现,所以效率也很高。设置了绘图方式之后,DC会自动保证反色,我们只管画连续的线即可。这就用上了原先我们用线条自由绘图的技术,而反色则只要设置绘图方式即可。
我们可以看看效果先:
设置绘图方式后自由的反色绘图
我们在客户区中画图,默认使用黑色的画笔。默认的绘图方式就是将画笔的颜色覆盖客户区对应的像素的颜色。这个模式叫做拷贝像素方式。那么客户区的像素我们叫做目标,也可以叫做画板,也可以叫做画布。我们调用函数SetROP2,传入R2_NOT参数,就可以将画板的像素取反绘画。也就是说,此时忽略画笔的颜色,最终在客户区上显示的颜色,由客户区当前的像素颜色每一位取反得到,如果客户区的颜色全是白色,那么在上面画的都是黑色的,如果客户区既有白色,也有黑色,那么画笔经过白色画黑线,经过黑色画白线。如果客户区有彩色,那么画笔经过后画的颜色就是RGB(255-红色分量,255-绿色分量,255-蓝色分量),三个颜色分量就是客户区的,用255去减掉分量后,最后形成的颜色就是反色了。所以,画笔经过红色后画的颜色就是青色,经过绿色客户区后画的是品色,经过蓝色就画的是黄色等等。你可以试试效果哦。而这一切,都是建立在客户区已有的颜色,第一次画图画的黑色,留下来之后,第二次画,就将上一次画的黑色作为客户区的这个点的像素,然后取反得到白色。每一次绘画都沉淀下来,成为客户区的颜色的一部分了。所以,在同一个位置画两次就成了客户区原本的颜色,反反得正的道理。
那么这个效果,我们只要简单的在绘画前设置绘图方式,然后就到达反色绘画的效果。至于你要画什么,则是你要做的事情。
最后说一下,这个绘图方式并不影响文字的输出,经过测试,文字输出始终在最顶层,而且设置什么颜色就输出什么颜色,与绘图方式无关。不信你可以在客户区鼠标移动时输出一个文字就可以看到了。我在提供的源码里,就有输出文字的代码。
下面是完整的代码:
#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;
TCHAR Info[100]=_T("■■■■■■■■■■■■■■");
static POINT ptOld;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);//会清除无效矩形
SetROP2(hdc,R2_NOT);
SetBkMode(hdc,TRANSPARENT);
SetTextColor(hdc,RGB(255,0,0));
TextOut(hdc,0,10,Info,lstrlen(Info));
Rectangle(hdc,10,150,300,300);//默认白色画刷,所以是白色的实心矩形
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_KEYDOWN:
InvalidateRect(hwnd,NULL,TRUE);
return 0;
case WM_MOUSEMOVE:
if(bisPaint)//如果按着鼠标时,表示在作画,因此可以开始绘制
{
hdc = GetDC(hwnd);
SetROP2(hdc,R2_NOT);
SetBkMode(hdc,TRANSPARENT);
SetTextColor(hdc,RGB(255,0,0));
//文本输出在最顶层
TextOut(hdc,10,100,_T("输出的文本测试是否反色显示,设置颜色为红色,反色后为青色"),lstrlen(_T("输出的文本测试是否反色显示,设置颜色为红色,反色后为青色")));
MoveToEx(hdc,ptOld.x,ptOld.y,NULL);
SelectObject(hdc,CreatePen(PS_SOLID,1,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;
}