LONG x;
LONG y;
LONG left;
LONG top;
LONG right;
LONG bottom;
CRect( int l, int t, int r, int b );
CRect( const RECT& srcRect );
CRect( LPCRECT lpSrcRect );
CRect( POINT point, SIZE size );
CRect( POINT topLeft, POINT bottomRight );
BOOL PtInRect( POINT point ) const;
CRect rect( 10, 10, 371, 267 );
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
// TODO: Add your message handler code here and/or call default
CView::OnSize(nType, cx, cy);
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXIMIZED(窗口已被最大化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MINIMIZED(窗口已被最小化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_RESTORED(窗口已被改变大小)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXHIDE(其他窗口被最大化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXSHOW(其他窗口从最大化还原)
void GetClientRect( LPRECT lpRect ) const;
在Windows中,绘图使用的是MFC的DC(Device-Context, 设备上下文)类CDC中各种绘图函数。
CDC* GetDC( );
int ReleaseDC( CDC* pDC ); // 成功返回非0
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
pDC->SelectObject(new CPen(PS_SOLID, 0, RGB(255, 0, 0)));
LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0,
HBRUSH hbrBackground = 0, HICON hIcon = 0 );
cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW |
CS_VREDRAW | CS_CLASSDC, 0,
return CView::PreCreateWindow(cs);
HDC GetSafeHdc();
来获取CD所对应窗口(如客户区)的安全DC句柄,该句柄在窗口存在期间一直是有效的。例如,可先定义类变量HDC m_hDC;,再在适当的地方给它赋值m_hDC = GetDC()->GetSafeHdc();,然后就可以放心地使用了。例如,可以使用CDC类的成员函数
BOOL Attach(HDC hDC); // 成功返回非0
typedef DWORD COLORREF; // 0x00bbggrr
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
BYTE bRed, // red component of color
BYTE bBlue // blue component of color
COLORREF red, gray;
red = RGB(255, 0, 0);
gray = RGB(128, 128,128);
#define GetRValue(rgb) (LOBYTE(rgb))
#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8))
#define GetBValue(rgb) (LOBYTE((rgb)>>16))
typedef ULONG_PTR DWORD_PTR;
pDC->SetPixel(10, 10, RGB(0, 255, 0));
<!--[if !supportLists]-->l <!--[endif]-->创建笔对象:创建笔类CPen对象的方法有如下两种:
<!--[if !supportLists]-->n <!--[endif]-->使用构造函数CPen
CPen( int nPenStyle, int nWidth, COLORREF crColor );
<!--[if !supportLists]-->u <!--[endif]-->nPenStyle为笔的风格,可取值:
PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PSDASHDOTDOT
<!--[if !supportLists]-->u <!--[endif]-->nWidth为笔宽,与映射模式有关,使用缺省映射时为像素数,若nWidth = 0,则不论什么映射模式,笔宽都为一个像素;
<!--[if !supportLists]-->u <!--[endif]-->crColor为笔的颜色值。
<!--[if !supportLists]-->n <!--[endif]-->使用成员函数CreatePen
BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );
<!--[if !supportLists]-->n <!--[endif]-->缺省的笔为单像素宽的实心黑色笔
<!--[if !supportLists]-->l <!--[endif]-->将笔对象选入设备上下文:为了能使用我们所创建的笔对象,必须先将它选入设备上下文,这可以调用设备上下文类CDC的成员函数SelectObject来完成:
<!--[if !supportLists]-->l <!--[endif]-->使用设备上下文画线状图:画线状图以及面状图的边线,所使用的是当前设备上下文中的笔对象。线状图有直线、折线、矩形、(椭)圆(弧)等,详见4)(2)
<!--[if !supportLists]-->l <!--[endif]-->将笔对象从设备上下文中放出:为了能删除使用过的笔对象,必须先将它从设备上下文中释放出来后,然后才能删除。释放的方法是装入其他的笔对象(一般是重新装入原来的笔对象)。例如
<!--[if !supportLists]-->l <!--[endif]-->删除笔对象:为了能删除笔对象,必须先将其从设备上下文中释放。删除方法有如下几种:
<!--[if !supportLists]-->n <!--[endif]-->调用笔类CDC的成员函数DeleteObject删除笔的当前内容(但是未删除笔对象,以后可再用成员函数CreatePen在笔对象中继续创建新的笔内容)。如
<!--[if !supportLists]-->n <!--[endif]-->使用删除运算符delete将笔对象彻底删除,如delete pen;
<!--[if !supportLists]-->n <!--[endif]-->自动删除:若笔对象为局部变量,则在离开其作用域时,会被系统自动删除
for (int j = 0; j <= 255; j++) {
HSLtoRGB(m_hue, m_sat, 255 - j, r, g, b); // 自定义的函数
pen.CreatePen(PS_SOLID, 0, RGB(r, g, b));
pOldPen = pDC->SelectObject(&pen);
pDC->MoveTo(0, j); pDC->LineTo(40, j);
<!--[if !supportLists]-->l <!--[endif]-->构造函数有4个:
<!--[if !supportLists]-->n <!--[endif]-->CBrush( ); // 创建一个刷的空对象
<!--[if !supportLists]-->n <!--[endif]-->CBrush( COLORREF crColor ); // 创建颜色为crColor的实心刷
<!--[if !supportLists]-->n <!--[endif]-->CBrush( int nIndex, COLORREF crColor ); // 创建风格由nIndex指定且颜色为crColor的条纹(hatch孵化)刷,其中nIndex可取条纹风格(Hatch Styles)值:
符号常量
|
数字常量
|
风格
|
HS_HORIZONTAL |
0
|
水平线
|
HS_VERTICAL |
1
|
垂直线
|
HS_FDIAGONAL |
2
|
正斜线
|
HS_BDIAGONAL |
3
|
反斜线
|
HS_CROSS |
4
|
十字线(正网格)
|
HS_DIAGCROSS |
5
|
斜十字线(斜网格)
|
<!--[if !supportLists]-->n <!--[endif]-->CBrush( CBitmap* pBitmap ); // 创建位图为pBitmap的图案刷
如:pDC->FillRect( &rect, new CBrush( RGB(r, g, b) ) );
<!--[if !supportLists]-->l <!--[endif]-->与构造函数相对应,有多个创建不同类型刷的成员函数:
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateSolidBrush( COLORREF crColor );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateHatchBrush( int nIndex, COLORREF crColor );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreatePatternBrush( CBitmap* pBitmap );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateDIBPatternBrush( HGLOBAL hPackedDIB, UINT nUsage );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateDIBPatternBrush( const void* lpPackedDIB, UINT nUsage );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateBrushIndirect( const LOGBRUSH* lpLogBrush );
<!--[if !supportLists]-->n <!--[endif]-->BOOL CreateSysColorBrush( int nIndex );
<!--[if !supportLists]-->l <!--[endif]-->预定义的刷对象有BLACK_BRUSH(黑刷)、DKGRAY_BRUSH(暗灰刷)、GRAY_BRUSH(灰刷)、HOLLOW_BRUSH(空刷)、LTGRAY_BRUSH(亮灰刷)、NULL_BRUSH(空刷)、WHITE_BRUSH(白刷)
<!--[if !supportLists]-->l <!--[endif]-->缺省的刷为空刷
<!--[if !supportLists]-->l <!--[endif]-->与笔一样,可以用函数SelectObject或SelectStockObject将自定义的刷或预定义的刷选入DC中,供绘面状图时使用。
pDC->TextOut(10, 10, "Test text");
pDC->SetTextColor(RGB(0, 128, 0)); pDC->TextOut(10, 30, "Test text");
pDC->SetBkColor(RGB(0, 0, 128)); pDC->TextOut(10, 50, "Test text");
Windows的图形设备接口(GDI = graphics device interface)对象指各种绘图工具,如笔、刷、位图、字体、调色板、区域等,对应的MFC类为CPen、CBrush、CBitmap、CFont等。这些图形绘制对象类都是CGDIObject的派生类,而CGDIObject则是直接从CObject类派生的抽象基类。<!--[endif]-->其中,Windws CE不支持调色板类CPalette;CRgn为区域类,对应于窗口中的一个矩形、多边形或(椭)圆区域(region),可用于移动、拷贝、合并、判断和裁剪。
HDC hdc, // handle to device context
UINT uObjectType // specifies the object-type
OBJ_PEN // Returns the current selected pen.
OBJ_PAL // Returns the current selected palette.
OBJ_FONT // Returns the current selected font.
CPen* GetCurrentPen( ) const;
CBrush* GetCurrentBrush( ) const;
CFont* GetCurrentFont( ) const;
CBitmap* GetCurrentBitmap( ) const;
CPalette* GetCurrentPalette( ) const;
HPEN hPen = (HPEN)GetCurrentObject(pDC->m_hDC, OBJ_PEN);
CPen* pPen = CPen::FromHandle(hPen);
CPen* pPen = pDC-> GetCurrentPen( );
缺省情况下,绘图的默认映射模式为MM_TEXT,其绘图单位为像素(只要不打印输出,屏幕绘图使用该模式就够了)。若窗口客户区的宽和高分别为w和h像素,则其x坐标是从左到右,范围为0 ~ w-1;y坐标是从上到下,范围为0 ~ h-1。
virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式
符号常量
|
数字常量
|
x方向
|
y方向
|
逻辑单位的大小
|
MM_TEXT |
1
|
向右
|
向下
|
像素
|
MM_LOMETRIC |
2
|
向右
|
向上
|
0.1 mm
|
MM_HIMETRIC |
3
|
向右
|
向上
|
0.01 mm
|
MM_LOENGLISH |
4
|
向右
|
向上
|
0.01 in
|
MM_HIENGLISH |
5
|
向右
|
向上
|
0.001 in
|
MM_TWIPS |
6
|
向右
|
向上
|
1/1440 in
|
MM_ISOTROPIC |
7
|
自定义
|
自定义
|
自定义
|
MM_ANISOTROPIC |
8
|
自定义
|
自定义
|
自定义
|
virtual CSize SetWindowExt( int cx, int cy );
virtual CSize SetViewportExt( int cx, int cy );
pDC->SetViewportExt(rect.right, -rect.bottom);
pDC->SetViewportOrg(rect.right / 2, rect.bottom /2);
pDC->Ellipse(CRect(-500, -500, 500, 500));
<!--[if !supportLists]-->l <!--[endif]-->CDC的成员函数(如各种绘图函数)具有逻辑坐标参数
<!--[if !supportLists]-->l <!--[endif]-->CWnd的成员函数(如各种响应函数)具有设备坐标参数(如鼠标位置point)
<!--[if !supportLists]-->l <!--[endif]-->位置的测试操作(如CRect的PtInRect函数)只有使用设备坐标时才有效
<!--[if !supportLists]-->l <!--[endif]-->长期使用的值应该用逻辑坐标保存(如窗口滚动后保存的设备坐标就无效了)
void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;
void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {
CRect rect = m_rect; // 逻辑坐标
if (rect.PtInRect(point)) // 位置的测试操作只有使用设备坐标时才有效
void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {
float t,y;
CDC* pDC = GetDC();
t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);
COLORREF SetPixel( int x, int y, COLORREF crColor ); 或
COLORREF SetPixel( POINT point, COLORREF crColor );
pDC->SetPixel(i, j, RGB(r, g, b));
<!--[if !supportLists]-->l <!--[endif]-->当前位置:设置当前位置为(x, y)或point:(返回值为原当前位置的坐标)
CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );
<!--[if !supportLists]-->l <!--[endif]-->画线:使用DC中的笔从当前位置画线到点(x, y)或point:(若成功返回非0值):
<!--[if !supportLists]-->l <!--[endif]-->画折线:使用DC中的笔,依次将点数组lpPoints中的nCount(≥2)个点连接起来,形成一条折线:
<!--[if !supportLists]-->l <!--[endif]-->画多边形:似画折线,但还会将最后的点与第一个点相连形成多边形,并用DC中的刷填充其内部区域:
<!--[if !supportLists]-->l <!--[endif]-->画矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用DC中的刷填充其内部区域:
rect = CRect(min(p0.x, point.x), min(p0.y, point.y), max(p0.x, point.x), max(p0.y, point.y));
<!--[if !supportLists]-->l <!--[endif]-->画圆角矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用宽x3或point.x高y3或point.y矩形的内接椭圆倒角,再用DC中的刷填充其内部区域:
int d = min(rect.Width(), rect.Height()) / 4;
<!--[if !supportLists]-->l <!--[endif]-->画(椭)圆:使用DC中的笔在左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形中画内接(椭)圆的边线,并用DC中的刷填充其内部区域:
<!--[if !supportLists]-->l <!--[endif]-->画弧:(x1, y1)与(x2, y2)或lpRect的含义同画(椭)圆,(x3, y3)或ptStart为弧的起点,(x4, y4)或ptEnd为弧的终点:(逆时针方向旋转)
BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);
<!--[if !supportLists]-->l <!--[endif]-->画弓弦:参数的含义同上,只是用一根弦连接弧的起点和终点,形成一个弓形,并用DC中的刷填充其内部区域:
BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
<!--[if !supportLists]-->l <!--[endif]-->画填充矩形:用指定的刷pBrush画一个以lpRect为区域的填充矩形,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界:
<!--[if !supportLists]-->l <!--[endif]-->画单色填充矩形:似FillRect,但只能填充单色,不能填充条纹和图案:
<!--[if !supportLists]-->l <!--[endif]-->画饼图(扇形):参数含义同Arc,但将起点和终点都与外接矩形的中心相连接,形成一个扇形区域,用DC中的刷填充整个扇形区域,无另外的边线:
BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
<!--[if !supportLists]-->l <!--[endif]-->画拖动的矩形:先擦除线宽为sizeLast、填充刷为pBrushLast的原矩形lpRectLast,然后再以线宽为size、填充刷为pBrush画新矩形lpRectLast。矩形的边框用灰色的点虚线画,缺省的填充刷为空刷:
void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,
SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );
如:pDC->DrawDragRect(rect, size, rect0, size);
<!--[if !supportLists]-->l <!--[endif]-->填充区域:
<!--[if !supportLists]-->n <!--[endif]-->用当前刷从点(x, y)开始向四周填充到颜色为crColor的边界:
BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0
<!--[if !supportLists]-->n <!--[endif]-->用当前刷从点(x, y)开始向四周填充:
BOOL ExtFloodFill(int x, int y, COLORREF crColor,
UINT nFillType); // 成功返回非0
pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);
LPCRECT lpRectUpdate = NULL,
UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE
pDC->FillSolidRect(&rect, RGB(255, 255, 255));
CDC* GetDC( );
// get control window and DC of Hue&Saturation
CWnd *pWin = GetDlgItem(IDC_HUESAT);
CDC *pDC = pWin->GetDC();
// draw hue-saturation palette
for (i = 0; i < 360; i++)
for (j = 0; j <= 255; j++) {
HSLtoRGB(i, 255 - j, 128, r, g, b); // 自定义函数,见网络硬盘的
pDC->SetPixel(i, j, RGB(r, g, b));
CWnd* pWnd = GetDlgItem(IDC_COLOR);
CDC* pDC = pWnd->GetDC();
CRect rect;
<!--[if !supportLists]-->l <!--[endif]-->除了基于对话框的程序外,其他对话框类都需要自己添加(重写型)消息响应函数OnInitDialog,来做一些必要的初始化对话框的工作。添加方法是:先在项目区选中“类视图”页,再选中对应的对话框类,然后在属性窗口的“重写”页中添加该函数;
<!--[if !supportLists]-->l <!--[endif]-->为了使在运行时能够不断及时更新控件的显示(主要是自己加的显式代码),可以将自己绘制控件的所有代码都全部加入对话框类的消息响应函数OnPaint中。在需要时(例如在绘图参数修改后),自己调用CWnd的Invalidate和UpdateWindow函数,请求系统刷新对话框和控件的显示。因为控件也是窗口,控件类都是CWnd的派生类。所以在对话框和控件中,可以像在视图类中一样,调用各种CWnd的成员函数。
<!--[if !supportLists]-->l <!--[endif]-->一般的对话框类,缺省时都没有明写出OnPaint函数。可以自己在对话框类中添加WM_PAINT消息的响应函数OnPaint来进行一些绘图工作。
<!--[if !supportLists]-->l <!--[endif]-->为了在鼠标指向按钮时,让按钮上自己绘制的图形不被消去,可以设置按钮控件的“Owner Draw”属性为“True”。
<!--[if !supportLists]-->l <!--[endif]-->如果希望非按钮控件(如图片控件和静态文本等),也可以响应鼠标消息(如单击、双击等),需要设置控件的“Notify”属性为“True”。
<!--[if !supportLists]-->l <!--[endif]-->使用OnPaint函数在对话框客户区的空白处(无控件的地方)绘制自己的图形,必须屏蔽掉其中缺省的对对话框基类的OnPaint函数的调用:
<!--[if !supportLists]-->l <!--[endif]-->对话框的背景色,可以用CWnd类的成员函数:
CColorDialog colDlg(m_crLineColor);
if (colDlg.DoModal() == IDOK) {
m_crLineColor = colDlg.GetColor();
CPaintDC dc(this); // device context for painting
FillColor(IDC_PEN_COLOR, m_crLineColor);
FillColor(IDC_BRUSH_COLOR, m_crBrushColor);
if(m_pBitmap0 != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp0);
else if(m_pBitmap != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp);
void CSetDlg::FillColor(UINT id, COLORREF col)
CWnd* pWnd = GetDlgItem(id);
CDC* pDC = pWnd->GetDC();
pDC->SelectObject(new CPen(PS_SOLID, 1, RGB(0, 0, 0)));
pDC->SelectObject(new CBrush(col));
pDC->RoundRect(&rect, CPoint(8, 8));
void CSetDlg::ShowImg(UINT ID, HBITMAP hBmp)
CWnd* pWnd = GetDlgItem(ID);
CDC* pDC = pWnd->GetDC();
GetObject(hBmp, sizeof(bs), &bs);
if(dc.CreateCompatibleDC(pDC)) {
float rx = (float)bs.bmWidth / rect.right,
ry = (float)bs.bmHeight / rect.bottom;
if (rx >= ry) {
x0 = 0; w = rect.right;
h = (int)(bs.bmHeight / rx + 0.5);
y0 = (rect.bottom - h) / 2;
y0 = 0; h = rect.bottom;
w = (int)(bs.bmWidth / ry + 0.5);
x0 = (rect.right - w) / 2;
::SelectObject(dc.GetSafeHdc(), hBmp);
pDC->StretchBlt(x0, y0, w, h, &dc, 0, 0, bs.bmWidth, bs.bmHeight, SRCCOPY);
SetDlgItemInt(IDC_W, bs.bmWidth);
SetDlgItemInt(IDC_H, bs.bmHeight);
nBkMode值
|
名称
|
作用
|
OPAQUE
|
不透明的(缺省值)
|
空隙用背景色填充
|
TRANSPARENT
|
透明的
|
空隙处保持原背景图不变
|
int SetROP2( int nDrawMode );
符号常量
|
作用
|
运算结果
|
R2_BLACK |
黑色
|
pixel = black |
R2_WHITE |
白色
|
pixel = white |
R2_NOP |
不变
|
pixel = scCol |
R2_NOT |
反色
|
pixel = ~scCol |
R2_COPYPEN |
覆盖
|
pixel = pbCol |
R2_NOTCOPYPEN |
反色覆盖
|
pixel = ~pbCol |
R2_MERGEPENNOT |
反色或
|
pixel = ~scCol | pbCol |
R2_MERGENOTPEN |
或反色
|
pixel = scCol | ~pbCol |
R2_MASKNOTPEN |
与反色
|
pixel = scCol & ~pbCol |
R2_MERGEPEN |
或
|
pixel = scCol | pbCol |
R2_NOTMERGEPEN |
或非
|
pixel = ~(scCol | pbCol) |
R2_MASKPEN |
与
|
pixel = scCol & pbCol |
R2_NOTMASKPEN |
与非
|
pixel = ~(scCol & pbCol) |
R2_XORPEN |
异或
|
pixel = scCol ^ pbCol |
R2_NOTXORPEN |
异或非
|
pixel = ~(scCol ^ pbCol) |
pGrayPen = new CPen(PS_DOT, 0, RGB(128, 128, 128));
<!--[if !supportLists]-->l <!--[endif]-->多边形填充方式:可使用CDC类的成员函数GetPolyFillMode和SetPolyFillMode来确定多边形的填充方式:
<!--[if !supportLists]-->l <!--[endif]-->画弧方向:可使用CDC类的成员函数GetArcDirection和SetArcDirection来确定Arc、Chord、Pie等函数的画弧方向:
<!--[if !supportLists]-->l <!--[endif]-->刷原点:可使用CDC类的成员函数GetBrushOrg和SetBrushOrg来确定可填充绘图函数的条纹或图案刷的起点:(缺省值为客户区左上角的坐标原点(0, 0))
BOOL m_bLButtonDown, m_bErase; // 判断是否按下左鼠标键
CPoint p0, pm; // 记录直线起点和动态终点的类变量
CPen * pGrayPen, * pLinePen; // 定义灰色和直线笔
m_bLButtonDown = FALSE; // 设左鼠标键按下为假
m_bErase = FALSE; // 设需要擦除为假
pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128));// 创建灰色笔
pLinePen = new CPen(PS_SOLID, 0, RGB(255, 0, 0));// 创建红色的直线笔
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {
m_bLButtonDown = TRUE; // 设左鼠标键按下为真
SetCapture(); // 设置鼠标捕获
// SetCursor(LoadCursor(NULL, IDC_CROSS)); // 设置鼠标为十字
p0 = point; // 保存矩形左上角
CView::OnLButtonDown(nFlags, point);
void CDrawView::OnMouseMove(UINT nFlags, CPoint point) {
SetCursor(LoadCursor(NULL, IDC_CROSS)); // 设置鼠标为十字
if (m_bLButtonDown) { // 左鼠标键按下为真
CDC* pDC = GetDC(); // 获取设备上下文
if (m_bErase) { // 需要擦除为真
pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直线
else // 需要擦除为假
pDC->MoveTo(p0); pDC->LineTo(point); // 绘制新直线
pm = point; // 记录老终点
ReleaseDC(pDC); // 释放设备上下文
CView::OnMouseMove(nFlags, point);
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) {
ReleaseCapture(); // 释放鼠标捕获
if (m_bLButtonDown) { // 左鼠标键按下为真
CDC* pDC = GetDC(); // 获取设备上下文
pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直线
pDC->MoveTo(p0); pDC->LineTo(point); // 绘制最终的直线
m_bLButtonDown = FALSE; // 重设左鼠标键按下为假
m_bErase = FALSE; // 重需要擦除为假
ReleaseDC(pDC); // 释放设备上下文
CView::OnLButtonUp(nFlags, point);