yang131

导航

MFC--教你如何使用画刷(2)

接下来我们用另外一个类CClientDC来实现我们的画线功能。

CClientDC是由CDC派生出来的一个类,在函数构造的时候就会去调用GetDC来获得一个句柄,而在析构的时候便调用ReleaseDC来释放一个句柄,来实现画线功能。

接下来让我们看一下代码的实现。

CClientDC dc(this);

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

 

 

如今实现了我们实现了在View视图内画线,那么,现在,我们如何实现在Frame框架上实现画线呢?

下面我将为你展示一下如何在Frame框架 上画图的实现:由于Frame是view的父窗口,要想实现此功能仅需在源代码中修改CClientDC dc(this)这句代码:

CClientDC dc(GetParent());

编译运行即可。

 

既然可以在工具栏上画图,那么又该如何实现在视图整个窗口画图呢。要想实现此功能,我们先要来认识一下WindowDC这个类,WindowDC是CDC派生出来的一个类,当在构造函数时,WindowDC会调用GetWindowDC来获得一个句柄,而在析构的时候去调用ReleaseDC来释放一个句柄。在视图类相应的类中编辑一下代码就可实现:

CWindowDC dc(GetParent());

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

编译运行即可。

 

我们再来看看如何实现在桌面窗口画图。首先,要介绍一下一个类,那就是GetDesktopWindow类,通过这个类我们就可以获得整个windows的桌面窗口。实现的原理就是这样。接下来让我们来看一下代码的实现:

CWindowDC dc(GetDesktopWindow());

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

 

学会了如何画出一条线,那么是不是要来看一下如何该变线条的颜色属性呢?首先,让我们来了解一下Cpen这个类:

CPen( int nPenStyle, int nWidth, COLORREF crColor );其中,第一个参数是画笔的类型,第二个参数是画笔的宽度,第三个参数是画笔的颜色,画笔的颜色可以通过RGB三原色来修改。

COLORREF RGB( BYTE byRed, // red component of color BYTE byGreen, // green component of color BYTEbyBlue // blue component of color );
接下来让我们看看代码的编辑:
Cpen pen(PS_SOLD,1,RGB(255,0,0)); //创建画笔
CClient dc(this);
Cpen *pOldPen=dc.SelectObject(&pen); //选用新的画笔去替换旧的画笔
dc.MOveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen); //选回旧的画笔
 
 
有了画笔,那么,如何创建画刷和位图画刷呢?首先来看一下画刷是个什么情况:画刷分为颜色画刷CBrush( COLORREF crColor )和位图画刷CBrush( int nIndex, COLORREF crColor )
CBrush( CBitmap* pBitmap ),先来看看颜色画刷:
CBrush brush(RGB(255,0,0)); //创建画刷
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush); //设计画刷
位图画刷的创建:位图画刷创建之后我们不能直接使用这个画刷,我们要使用他的初始化函数初始化之后才能使用。
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
CBrush brush(&bitmap);
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);
到这里就有一个很有趣的问题了,在很多地方我们需要的不仅仅是位图的全部,有时候我们只需要他的一部分,比如只需框架就行,这时候,我们就需要一个透明的画刷。那么我们怎么样才可以去获得一个透明的画刷呢?我们可以试着从CBrush中找,但是结果很是糟糕。那怎么办呢,别急别急,我们还有一个好东西,就是GetStockObject这个类,但是,问题又来了,我们的GetStockObject返回的是一个句柄,而我们现在需要的是一个对象,我们该如何把一个句柄转换成一个对象呢?这是我们就要用到另一个类,那就是FromHandle,这个类的作用是:Returns a pointer to a CBrush object when given a handle to a Windows HBRUSH object.,即让一个句柄转化成一个C++类的指针返回。问题决绝的差不多了,我们来试着实现一下吧:
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush *pOldBrush=dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);
这里又有个有趣的问题:那就是在
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));这句中我们引用FromHandle是不是用的点引用的方法,而是用两个冒号引用,这是为什么呢?这是因为
static CBitmap* PASCAL FromHandle( HPALETTE hPalette );
在这里,FromHandle是定义为静态的变量,在引用静态变量的时候,我们可以用两个冒号,因为静态的变量在我们调用这个类的时候已经在内存内为它分配好了内存空间,所以可以直接引用,而非静态的函数变量或类就只能用点引用方法引用。
 
 
到这里,画图,我们就只剩下一个知识点了,那就是实现画笔画连续曲线的功能。
要画出一条连续的曲线,我们首先还是要捕捉到画笔的起点,要捕捉到其他的点,我们就要有一个鼠标移动的消息,在鼠标移动中做一个命令响应,通过这个命令传进来的点不断的画一条条很短很短的线段,吧线段全部连起来之后就是一条曲线了。按照这种思路,我们就来写写代码,看看如何实现这种功能:
1、在view类上右击,添加windows中的MOUSEMOVE消息处理。这个消息只要我们的鼠标有移动就会把消息传进来,这并不是我们想要的,我们要的是,当鼠标左键按下去之后的点,知道鼠标左键松开时的所有的点传进来,开始作图。这时候,我们可以设置一个bool类型的变量,来判断是否按下了鼠标左键。当鼠标左键按下去的时候,我们把这个变量设置为真,当鼠标左键松开的时候,就设置为假。
2、在view类上右击,添加一个成员变量。在view的构造函数中把这个变量初始化为FALSE。当鼠标左键按下去的时候,我们把这个变量设置为TRUE。当鼠标左键弹起来的时候,我们把这个变量设置为FALSE。
3、首先创建一个DC,然后在鼠标移动里面先判断一下。实现代码如下:
CClientDC dc(this);
//CPen pen(PS_SOLD,1,RGB(255,0,0));
//CPen *pOldPen=dc.SelectObject(&pen);
if(m_Draw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point); //在这里,我们要稍稍做一下手脚,到这里,第一小段的线段画完了,作为一条,我们还要继续画小线段,这是就要把原来的终点变成现在的始点了
m_ptOrigin=point;
}
//dc.SelectObject(pOldPen);
添加注释掉的部分可以改变曲线的颜色哦亲。
 
画了曲线,就一定可以画出扇形滴,我们来看看怎么画出个扇形。
1、我们先添加一个私有成员变量用来标记上一线条的终点,m_ptOld,并在构造函数中对其做初始化m_pOld=0,当鼠标左键按下去的时候,我们就让ptOld等于原点。
2、在鼠标移动命令里面添加代码。首先,我们从m_ptOrigin出发,划出一条线到m_ptOld,然后再画一条线从m_ptOrigin到point。代码如下:

CClientDC dc(this);
//CPen pen(PS_SOLD,1,RGB(255,0,0));
//CPen *pOldPen=dc.SelectObject(&pen);
if(m_Draw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_pOld); //在这里,我们要稍稍做一下手脚,到这里,第一小段的线段画完了,作为一条,我们还要继续画小线段,这是就要把原来的终点变成现在的始点了
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOld=point;
}
//dc.SelectObject(pOldPen);
 
嘻嘻,人类的贪婪是不会得到满足滴哦,让我们在来画带边界的扇形吧。这时我们只要做小小的改动就可以实现哦。
我们只要把dc.MoveTo(m_ptOrigin)这句改为:dc.MoveTo(m_ptOld),这样,我们就大功告成了。
我们的MFC画图学习到这就差不到了,在这里,祝各位看我的博客的读者学有所成,当然,如果有什么不足之处,还请见谅。
到这,我还有送读者一个函数:SetROP2
这个函数主要是用来设置绘画模式的一个函数,在这个函数中只有一个参数,用来设置绘画模式,一下是这个函数的可用参数:

Parameters

nDrawMode
The new drawing mode. It can be any of the following values:
  • R2_BLACK    Pixel is always black.
  • R2_WHITE    Pixel is always white.
  • R2_NOP    Pixel remains unchanged.
  • R2_NOT    Pixel is the inverse of the screen color.
  • R2_COPYPEN    Pixel is the pen color.
  • R2_NOTCOPYPEN    Pixel is the inverse of the pen color.
  • R2_MERGEPENNOT   Pixel is a combination of the pen color and the inverse of the screen color (final pixel = (NOT screen pixel) OR pen).
  • R2_MASKPENNOT    Pixel is a combination of the colors common to both the pen and the inverse of the screen (final pixel = (NOT screen pixel) AND pen).
  • R2_MERGENOTPEN   Pixel is a combination of the screen color and the inverse of the pen color (final pixel = (NOT pen) OR screen pixel).
  • R2_MASKNOTPEN    Pixel is a combination of the colors common to both the screen and the inverse of the pen (final pixel = (NOT pen) AND screen pixel).
  • R2_MERGEPEN    Pixel is a combination of the pen color and the screen color (final pixel = pen OR screen pixel).
  • R2_NOTMERGEPEN   Pixel is the inverse of the R2_MERGEPEN color (final pixel = NOT(pen OR screen pixel)).
  • R2_MASKPEN    Pixel is a combination of the colors common to both the pen and the screen (final pixel = pen AND screen pixel).
  • R2_NOTMASKPEN    Pixel is the inverse of the R2_MASKPEN color (final pixel = NOT(pen AND screen pixel)).
  • R2_XORPEN    Pixel is a combination of the colors that are in the pen or in the screen, but not in both (final pixel = pen XOR screen pixel).
  • R2_NOTXORPEN    Pixel is the inverse of the R2_XORPEN color (final pixel = NOT(pen XOR screen pixel)).

posted on 2020-06-24 17:26  NoNight  阅读(840)  评论(0编辑  收藏  举报