第四课:画线
一、 GDI、DC的概念
1. GDI:(Graphics Device Interfase)图形设备接口,是一个应用程序与输出设备之间的中介。一方面,GDI向应用程序提供一个与设备无关的编程环境,另一方面,它又以设备相关的格式和具体的设备打交道。
2. DC:(Device Context)设备描述表,是一种Windows数据结构。包括了与一个设备的绘制属性相关的信息。所有的绘制操作通过一个设备描述表进行,绘制线条、形状和文本的Windows API 函数都与DC有关。
二、 在Windows Application程序中画线
1. 定义两个全局变量用于记录鼠标按下的(x,y)坐标。
int nOrginX;
int nOrginY;
这两个变量如果定义为局部变量,放在Switch—Case语句中和回调函数中都将画不出线来。
2. 响应鼠标按下和鼠标抬起的消息:
在Swich中加入case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
3. 在鼠标按下时记录鼠标按下的(x,y)坐标,查MSDN得知WM_LBUTTONDOWN
lParam的低字存放x坐标,高字存放y坐标,将其取出存入nOrginX,nOrginY。
case WM_LBUTTONDOWN:
nOrginX=lParam & 0x0000ffff;
nOrginY=lParam >> 16 & 0x0000ffff;
break;
4. 在鼠标抬起时画线:
case WM_LBUTTONUP:
HDC hdc;
hdc=GetDC(hwnd);
PAINTSTRUCT ps;
::MoveToEx(hdc,nOrginX,nOrginY,NULL);
::LineTo(hdc,LOWORD(lParam),HIWORD(lParam) );
::ReleaseDC(hwnd,hdc);
三、在MFC程序中画线:
1. 在CxxxView(其中xxx是你的工程名字)中响应鼠标按下和鼠标抬起的消息(因为只有CxxxView中才能接收到鼠标消息):
使用ClassWizard加入WM_LBUTTONDOWN,WM_LBUTTONUP的消息响应函数OnLButtonDown, OnLButtonUp。
2. 在CxxxView中添加成员变量CPoint m_ptOrigin,用于记录鼠标按下的(x,y)坐标。
CPoint是一个用于描述点的简单的类,它有两个成员变量可以存放点的(x,y)坐标。
3. 在鼠标按下时记录该点的坐标:
m_ptOrigin =point;
其中point是调用OnLButtonDown传入的鼠标按下的点的坐标。
4. 在鼠标抬起时画线:
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
其中CClientDC 是一个CDC的子类,在它的构造函数中调用了GetDC,析构函数中调用了ReleaseDC,简化了用户的操作。
三、 实现橡皮筋功能:
1. 再定义一个成员变量,用于记录鼠标抬起的点,以便擦线。
CPoint m_ptEnd;
2. 在鼠标按下时记录该点的坐标:
m_ptOrigin=m_ptEnd=point;
3.使用ClassWizard加入WM_MOUSEMOVE的消息响应函数OnMouseMove。
在鼠标移动时判断鼠标左鍵是否按下,如果按下,就不断地擦去上一条线,画出鼠标按下点到鼠标移动的当前点之间的线。
if(MK_LBUTTON & nFlags)
{
CClientDC dc(this);
dc.SetROP2(R2_NOT);
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptEnd);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptEnd=point;
}
其中:
if (MK_LBUTTON & nFlags)
是判断鼠标左鍵是否按下。在调用OnMouseMove时,不仅为用户传来了坐标信息,还把鼠标左鍵是否按下,Shift鍵是否按下(详细信息可查MSDN)等信息放在UINT nFlags中传入OnMouseMove,用户可以检查相应位是否为1来判断相应键是否按下。
dc.SetROP2(R2_NOT);
该句设置逆转当前屏幕颜色的绘图模式。这种模式下,在屏幕上首次画出的线的是可见的,但在同一位置再画一遍时,线就不见了。这样可以方便的实现不断画线、擦线的效果。
四、 生成自定义的笔和刷子:
1. Windows的GDI对象:
A. CPen : 笔是一促用来画线及绘制有形边框的工具,可以指定它的颜色及宽度,并且可以指定它的线型(实线、点线、虚线等)。
B.CBrush : 刷子定义了一种位图形式的象素,利用它可以对区域内部填充颜色。
C.CFont :字体是一种具有某种风格和尺寸的所有字符的完整集合。
D.CBitmap:位图是一种位矩阵,每一个显示象素都对应于其中的一个或多个位,可以利用位图来表示图象,也可以利用它来创建刷子。
E.CRgn :区域是由多边形、椭圆或二者组合形成的一种范围,可以利用它来进行填充、裁剪以及点中测试。
2. SelectObject函数:
当用户生成一个GDI对象时,它是不会生效的。必须用SelectObject将该GDI对象选入设备描述表,它才会在以后的绘制操作中生效。SelectObject函数会返回指向前一次被选对象的指针。
3. 自定义画笔:
CPen 类提供构造函数用于产生Cpen可以定义笔的线型、线宽和颜色。
CPen( int nPenStyle, int nWidth, COLORREF crColor );
程序中,生成了一个实线,宽度为6,颜色为黑色的笔。要注意的是,有的线型只在线宽小于1时才有效。
CPen newpen(PS_SOLID ,6,RGB(0,0,0));
dc.SelectObject(&newpen);
4. 自定义刷子:
CBrush 提供用于产生刷子的构造函数:
CBrush( COLORREF crColor );
CBrush( int nIndex, COLORREF crColor );
CBrush( CBitmap* pBitmap );
I. CBrush( COLORREF crColor );
它可以产生某种颜色的实心刷子,下面的代码产生了一个红色的实心刷子。
CBrush br(RGB(255,0,0));
dc.SelectObject(&br);
II. CBrush( int nIndex, COLORREF crColor );
它可以产生某种剖面线的刷子,下面的代码产生了一个红色的剖面线刷子。
CBrush br(HS_FDIAGONAL,RGB(255,0,0));
dc.SelectObject(&br);
III. CBrush( CBitmap* pBitmap );
它可以产生位图刷子。
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
CBrush br(&bmp);
dc.SelectObject(&br);
这段代码首先装入了一幅位图(先在资源中添加一个位图资源,其ID指定为IDB_BITMAP1),再根据这幅位图产生了一个位图刷子。
IV. 产生空刷子
空刷子是一种特殊的刷子,有两种方法可以产生。
1) LOGBRUSH logbr;
logbr.lbStyle=BS_NULL;
br.CreateBrushIndirect(&logbr);
dc.SelectObject(&br);
2)HBRUSH hbr=(HBRUSH)::GetStockObject(NULL_BRUSH);
CBrush *pbr;
pbr=CBrush::FromHandle(hbr);
dc.SelectObject(pbr);
其中,CBrush::FromHandle是一个静态成员函数,它可以不生成类的实例而直接调用,但前面一定要加上类名,以表示它是哪个类的成员函数。
评论