VC++画图


当我们鼠标左键按下时,就有了一个点(消息响应,捕获其中一点),即源点

按住鼠标左键拖动,到左键松开的时候就有了另外一个点了。即终点

也就是说我们需要捕获两个消息按下和弹起,消息响应中能获取到两个点。

首先我们用的是API函数(全局的::)

要想作图,首先要获取一个DC的句柄。

全局SDK用::

当前VIEW类窗口的句柄m_hWnd;

MoveToEX

BOOL MoveToEx(
__in HDC hdc,
__in int X,
__in int Y,
__out LPPOINT lpPoint
);

The MoveToEx function updates the current position to the specified point and optionally returns the previous position.

更新当前的点到指定的点,选择性地返回先前的点。

BOOL LineTo(
__in HDC hdc,
__in int nXEnd,
__in int nYEnd
);

用当前画笔画一条线,从当前位置连到一个指定的点。这个函数调用完毕,当前位置变成x,y

当然别忘了释放DC

::ReleaseDC(m_hWnd,hdc)

代码如下:

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
 m_ptOrigin=point;//这点在构造函数里要有定义

CView::OnLButtonDown(nFlags, point);
}


void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
HDC hdc;
 hdc=::GetDC(m_hWnd);//全局的
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);
CView::OnLButtonUp(nFlags, point);
}


而在MFC中给我们提供了一个类了CDC

从CObject派生出来

CWnd::GetDC这和全局的GetDC是不一样的,见上文

这里用到是MoveTo不是MoveToEx。

Moves the current position to the point specified by x and y (or by point).

移动当前的点到用x,y指定的点或

point:

Specifies the new position. You can pass either a POINT structure or a CPoint object for this parameter

有两个版本:

CPoint MoveTo(
int x,
int y
);
CPoint MoveTo(
POINT point
);

接下来用CDC::LineTo,不解释

当然还得释放ReleaseDC。

关键代码:

CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);

这样更容易地画出了一条直线。


下面我们再换一个方式:(这么多方法?)

这里又有一个类了CClient,派生自CDC

构造的时候调用GetDC,析构的时候调用ReleaseDC

CClientDC dc(this);因为是在View类里作图,所以直接用this指针传递

这里构造的是对象不是指针所以用点操作符调用成员函数

这样又一种方法又产生了(一种比一种包装的深)

代码:

CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

如果把this换成GetParent()的话我们发现画线都能画到工具栏上面。

这个函数能返回指向父窗口的指针。

而Cview是从CFrame派生来的


接下来又讲了一个CwindowDC类,哎两个多小时的视频

还是从CDC派生来的

构造的时候调用GetDC,析构的时候调用ReleaseDC

比CCLient还高级

最牛逼的地方在于它的对象能访问屏幕区域,包括客户区和非客户区。

一样的,它需要一个Cwnd的指针去构造。

参数为this和GetParent()的时候不咋样,

C++6.0能到画到标题栏,2010就不能了

如果参数用的是GetDesktopWindow()那就牛逼了,直接画到了桌面上了。


下面我们看一下如何画出其他颜色的线条

上面的程序用的是缺省的画笔。我们可以创建画笔,然后选到我们的设备描述表中

画笔类CPen

CPen::CPen

CPen(
int nPenStyle,
int nWidth,
COLORREF crColor
);
CPen(
int nPenStyle,
int nWidth,
const LOGBRUSH* pLogBrush,
int nStyleCount = 0,
const DWORD* lpStyle = NULL
);

例如Pen(PS_SOLID, 2, RGB(255,0,0))

第二个参数为笔的宽度,

COLORREF RGB

(BYTE byRed,

BYTE byGreen,

BYTE byBlue)

三个参数取值范围都是0-255.

(0,0,0)为黑

(255,255,255)为白

代表了红绿蓝三原色。相当于调色板

笔创建完之后要把笔选到设备描述表中

CDC::SelectObject()当然做完之后要选择回去

代码:

CPen pen(PS_SOLID, 2, RGB(255,0,0));
CClientDC dc(this);
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
 dc.SelectObject(&pen);//选择回去

注意PS_DASH为画阴影线,MSDN上说了,必须是宽度小于等于1时才有效

类似PS_DOT等画笔风格


接下来是画刷的创建(画刷用来填充一块矩形区域)

又是类CBrush,可以用一种颜色去构造画刷(RGB)

用到函数FillRect(),用指定的画刷去填充矩形区域,第一个参数为矩形区域(CRect的构造函数),第二个参数当然就是画刷了。

我们现在正好有两个点,两点也可以确定一个矩形哦。

上代码:

CBrush brush(RGB(255,0,0,));
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);

完事,矩形就这么画出来了


还是画矩形,但是是空心的

用Rectangle(可以用CRect(去构造)

BOOL Rectangle(
int x1,
int y1,
int x2,
int y2
);
BOOL Rectangle(
LPCRECT lpRect
);

代码:

dc.Rectangle(CRect(m_ptOrigin,point));

画出来就发现会相互覆盖,怎么办呢?创建透明画刷

用到了GetStockObject(NULL_BRUSH)

The GetStockObject function retrieves a handle to one of the stock pens, brushes, fonts, or palettes.

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));

各种转换啊。

(1)CBrush::FromHandle

Returns a pointer to a CBrush object when given a handle to a Windows HBRUSH object.

返回一个指向一个对象CBrush的指针,当给一个窗口句柄HBRUSH对象
即把句柄转换为了指针。
(2)
而GetStockObject返回的是HGDIOBJ,需要的是HBRUSH,所以要强制转换
当然,别忘了把画刷选到设备描述表中,然后还得选择回去SelectObject()
现在画出来的矩形就不会互相覆盖了。


那么我们怎么来画曲线呢?
首先,应该添加一个变量m_bDraw,初始值为FALSE。
在OnLButtonDown中设置为TRUE,OnLButtonUp中设置为False。
然后还得添加一个消息响应OnMouseMove。然后在MouseMove里判断m_bDraw的真值。真的时候就表示鼠标按下,假的时候表示鼠标弹起。
妙啊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
然后循环,每次画一个小线段,不断改变那两个点,呵呵,跟微积分似的。
先写这么多了。遇到一个很郁闷的问题

就是鼠标没按下的情况下就开始画了。真郁闷,后来是==号弄成了=号,导致if的判断条件一直为 真。发论坛上明眼人给我找了出来呵呵。
代码如下:
CClientDC dc(this);
  CPen *pOldPen=dc.SelectObject(&pen);
 if(m_bDraw==TRUE)//这里弄错了,导致我的错误半天楞是没看出来。
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin=point;
}
 
当然,同样地可以修改画笔
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin=point;
}
dc.SelectObject(pOldPen);

接下来我们试试画个扇形,首先得再增加一个变量

关键代码:

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)

m_ptOrigin=m_ptOld=point;//鼠标按下时,这个函数捕获了当前点,即point,然后再赋给这两个点


void CDrawView::OnMouseMove(UINT nFlags, CPoint point)

CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin);
  dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOld=point;
}
dc.SelectObject(pOldPen);

上边这几行看不怎么明白,不知道老师怎么想的

反正我用

dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

这两行就实现了。

好像是为了讲后面的带边线用的

dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOld);
dc.LineTo(point);
m_ptOld=point;

不咋明白,以后回来看吧




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值