最实用的GDI辅助类
来源:互联网 发布:JS确认框怎么设置 编辑:程序博客网 时间:2024/06/05 04:42
作者:SleepSheep
下载源代码
整体效果图:
有多少次你曾写下过类似的代码:
void Draw(CDC *pDC){ CPen MyPen; MyPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); CPen *pOldPen = pDC->SelectObject(&MyPen); // 用pen画 // 对于brush、font等重复以上的动作 pDC->SelectObject(pOldPen); // 重置之前的pen}
如果你没有用MFC类来写,你可能会用以下相似的方法:
void Draw(HDC hDC){ HPEN hMyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); HPEN hOldPen = SelectObject(hDC, hMyPen); //用pen来画 //对于brush、font等重复以上的动作 SelectObject(hDC, hOldPen); // 重置之前的pen DeleteObject(hMyPen); // 销毁新建的pen}
大部分的C/C++ Windows程序可能都充斥着这样的代码。那这样的代码有什么问题呢?主要的几个问题如下:
- 冗余
你必须要写四行代码才能将一个简单的pen选入到DC中,而且对于font、bitmap、brush等也要重复同样的操作。 - 错误
如果是直接用WIN32 API来写,你必须要记得,在函数返回前将旧的pen选入到DC中,并可能还需要将新的pen销毁掉。除此之外,如果有错误处理或多个return语句,你必须以某一种方式来确保函数中每条执行路径最终都会将原始的pen选回到DC中。在之前的例子中,假设注释的部分有一个return语句或发生了一个错误,你必须记得对以原始的pen为参数调用SelectObject,也许还需要调用DeleteObject。 - 复杂
你不得不将大量的参数传给函数用来创建pen、font、brush、bitmap等,尽管有些参数的默认值会在一定程度上对你有所帮助。(MFC库确实用了一些默认的参数,但像CPen::CreatePen()以及CFong::CreateFont()这样的成员中却并没有经常用)。
MFC代码如果能写成如下形式岂不是很好:
void Draw(CDC *pDC){ CVCKSelectPen MyPen(pDC, RGB(255, 0, 0)); // 就一行 //用pen来画 //原始的pen会自动被选回DC中 }
或者非MFC的代码写成这种样子:
void Draw(HDC hDC){ CVCKSelectPen MyPen(hDC, RGB(255, 0, 0)); //就一行 //用pen来画 //原始的pen会自动被选回DC中 }
前面的代码有以下几个优点:
- 简洁
一行代码就可以创建pen并将它选入到DC中,在你用完后会将它从DC中拿掉,在必要的时候会将pen销毁掉。 - 强健
不管你如何退出程序,原始的pen会通过CVCKSelectPen的析构函数重新被选回到DC中,即使是有错误发生或有好几个return语句。 - 简单易用
许多默认的参数已在pen的创建函数中传入了,许多成员函数(如创建brush需要的那些)都有重载,使得可以使用不一样的参数。
下面简单的就几个类及它们的使用方法来做一些介绍。
class CVCKSelect{ protected: CDC * const m_pDC; CVCKSelect(CDC * pDC):m_pDC(pDC) { ASSERT(m_pDC);} virtual ~CVCKSelect() {}};// Penclass CVCKSelectPen : public CVCKSelect{ CPen * m_NewPen; CPen * m_pOldPen;public: CVCKSelectPen(CDC * pDC) :CVCKSelect(pDC),m_pOldPen(NULL){} CVCKSelectPen(CDC * pDC, COLORREF col, int sty=PS_SOLID, int wid=0) :CVCKSelect(pDC) { VERIFY(m_NewPen.CreatePen(sty,wid,col)); VERIFY(m_pOldPen=m_pDC->SelectObject(&m_NewPen)); } CVCKSelectPen(CDC * pDC, CPen * pPen) :CVCKSelect(pDC) { ASSERT(pPen); VERIFY(m_pOldPen=m_pDC->SelectObject(pPen)); } ~CVCKSelectPen() { if (m_pOldPen) VERIFY(m_pDC->SelectObject(m_pOldPen)); } void Select(CPen * pPen) { ASSERT(pPen); ASSERT(pPen!=&m_NewPen); CPen * old=m_pDC->SelectObject(pPen); ASSERT(old); if (!m_pOldPen) m_pOldPen=old; m_NewPen.DeleteObject(); } void Select(COLORREF col, int sty=PS_SOLID, int wid=0) { if (m_pOldPen) Select(m_pOldPen); VERIFY(m_NewPen.CreatePen(sty,wid,col)); VERIFY(m_pOldPen=m_pDC->SelectObject(&m_NewPen)); } void Restore() { if (m_pOldPen) VERIFY(m_pDC->SelectObject(m_pOldPen)); m_pOldPen=NULL; m_NewPen.DeleteObject(); } CPen * Old() const { return m_pOldPen; }};// Brushclass CVCKSelectBrush : public CVCKSelect{ CBrush * m_NewBrush; CBrush * m_pOldBrush;public: CVCKSelectBrush(CDC * pDC) :CVCKSelect(pDC),m_pOldBrush(NULL) { } // Solid brush CVCKSelectBrush(CDC * pDC, COLORREF crColor) :CVCKSelect(pDC) { VERIFY(m_NewBrush.CreateSolidBrush(crColor)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // Hatch brush CVCKSelectBrush(CDC * pDC, int index,COLORREF crColor) :CVCKSelect(pDC) { VERIFY(m_NewBrush.CreateHatchBrush(index,crColor)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // Pattern brush CVCKSelectBrush(CDC * pDC, CBitmap * pBitmap) :CVCKSelect(pDC) { ASSERT(pBitmap); VERIFY(m_NewBrush.CreatePatternBrush(pBitmap)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // DIB Pattern brush CVCKSelectBrush(CDC * pDC,HGLOBAL hPackedDib,UINT usage) :CVCKSelect(pDC) { VERIFY(m_NewBrush.CreateDIBPatternBrush(hPackedDib,usage)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } CVCKSelectBrush(CDC * pDC, CBrush * pBrush) :CVCKSelect(pDC) { ASSERT(pBrush); VERIFY(m_pOldBrush=m_pDC->SelectObject(pBrush)); } ~CVCKSelectBrush() { if (m_pOldBrush) VERIFY(m_pDC->SelectObject(m_pOldBrush)); } void Select(CBrush * pBrush) { ASSERT(pBrush); ASSERT(pBrush!=&m_NewBrush); CBrush * old=m_pDC->SelectObject(pBrush); ASSERT(old); if (!m_pOldBrush) m_pOldBrush=old; m_NewBrush.DeleteObject(); } // Solid brush void Select(COLORREF col) { if (m_pOldBrush) Select(m_pOldBrush); VERIFY(m_NewBrush.CreateSolidBrush(col)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // Hatch brush void Select(int index,COLORREF col) { if (m_pOldBrush) Select(m_pOldBrush); VERIFY(m_NewBrush.CreateHatchBrush(index,col)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // Pattern brush void Select(CBitmap * pBitmap) { if (m_pOldBrush) Select(m_pOldBrush); VERIFY(m_NewBrush.CreatePatternBrush(pBitmap)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } // DIB Pattern brush void Select(HGLOBAL hPackedDib,UINT usage) { if (m_pOldBrush) Select(m_pOldBrush); VERIFY(m_NewBrush.CreateDIBPatternBrush(hPackedDib,usage)); VERIFY(m_pOldBrush=m_pDC->SelectObject(&m_NewBrush)); } void Restore() { if (m_pOldBrush) VERIFY(m_pDC->SelectObject(m_pOldBrush)); m_pOldBrush=NULL; m_NewBrush.DeleteObject(); } CBrush * Old() const { return m_pOldBrush; }};// Fontclass CVCKSelectFont : public CVCKSelect{ CMyFont m_NewFont; CFont * m_pOldFont;public: CVCKSelectFont(CDC * pDC) :CVCKSelect(pDC),m_pOldFont(NULL) { } CVCKSelectFont(CDC * pDC,int size,LPCTSTR face=NULL,BOOL bold=0, BOOL italic=0, BOOL underlined=0,BOOL fixed=0, BOOL hiquality=0,int angleindegrees=0) :CVCKSelect(pDC) { VERIFY(m_NewFont.MyCreateFont(m_pDC,size,face,bold,italic, underlined,fixed,hiquality,angleindegrees)); VERIFY(m_pOldFont=m_pDC->SelectObject(&m_NewFont)); } CVCKSelectFont(CDC * pDC, CFont * pFont) :CVCKSelect(pDC) { ASSERT(pFont); VERIFY(m_pOldFont=m_pDC->SelectObject(pFont)); } ~CVCKSelectFont() { if (m_pOldFont) VERIFY(m_pDC->SelectObject(m_pOldFont)); } void Select(CFont * pFont) { ASSERT(pFont); ASSERT(pFont!=&m_NewFont); CFont * old=m_pDC->SelectObject(pFont); ASSERT(old); if (!m_pOldFont) m_pOldFont=old; m_NewFont.DeleteObject(); } void Select(int size,LPCTSTR face=NULL,BOOL bold=0, BOOL italic=0,BOOL underlined=0,BOOL fixed=0, BOOL hiquality=0,int angleindegrees=0) { if (m_pOldFont) Select(m_pOldFont); VERIFY(m_NewFont.MyCreateFont(m_pDC,size,face,bold,italic, underlined,fixed,hiquality,angleindegrees)); VERIFY(m_pOldFont=m_pDC->SelectObject(&m_NewFont)); } void Restore() { if (m_pOldFont) VERIFY(m_pDC->SelectObject(m_pOldFont)); m_pOldFont=NULL; m_NewFont.DeleteObject(); } CFont * Old() const { return m_pOldFont; }};
CVCKSelect是这些类的基类,它里面存了一个CDC指针。
CVCKSelectPen、CVCKSelectBrush和CVCKSelectFont都派生自CVCKSelect,它们都对各自的构造函数和Select方法进行了重载。只要有合适的参数,一般只要构造函数那一步就可以将新的GDI对象建立出来并将它选入DC中,有时还可以再调用Select方法做一些修改。析构函数对会自动将原始的GDI对象选入DC中,并把新建的GDI对象销毁掉。Restore方法可以让使用者自己控制这一过程。Old方法会返回原始的GDI对象。
以上只展示了一部分GDI对象的封装,其他的请参考源代码。
以下是使用这些类的一个小例子:
void Draw(CDC * pDC) { CVCKSelectPen Pen(pDC,RGB(255,0,0)); CVCKSelectBrush Brush(pDC,HS_BDIAGONAL,RGB(0,255,0)); CVCKSelectFont Font(pDC,18,"Arial",TRUE); CVCKSelectTextColor TxtCol(pDC,RGB(0,0,255)); CVCKSelectTextAlign TxtAlg(pDC,TA_CENTER|TA_BASELINE); CVCKSelectBkMode BkMode(pDC,TRANSPARENT); // 绘制操作 // 新建的一些GDI对象会被自动释放,DC也会自动回复。 }
以brush为例,有的时候要等到运行时才能确定到底该要创建什么样的,如下所示:
if (Condition1) { // 选择 Hatch Brush } else { // 选择 Solid Brush } // 使用brush
这时,不能在某个条件下放一个CVCKSelectBrush对象,这样当出了if/else范围后那个对象的生命周期就结束了,DC中还是原来的brush。这个时候,我们要先在if/else之外用只接受一个CDC*为参数的构造函数建立一个CVCKSelectBrush对象,再在if/else中调用Select:
CSelBrush SelBrush(pDC); if (Condition1) { SelBrush.Select(HS_BDIAGONAL,RGB(255,0,0)); } else { SelBrush.Select(RGB(255,0,0)); } // 使用brush
需要注意的是,在一个函数中,每一中GDI对象(pen、bursh……)或每一种DC的属性(text color、map mode……)都只能用一个对象来操作。
如果你不想要反复的使用这些类,而且你对性能上的一些牺牲可以忍受的话,那可以用CSaveDC。在创建时它会保存整个的DC,等它销毁的时候会将DC还原。
- 最实用的GDI辅助类
- 关于 GDI+ 绘图的辅助类
- DevBox:最实用的移动开发辅助工具包
- 最实用的DBHelper类
- 实用辅助类-gzip解压类封装
- 最简单的GDI+程序代码
- GDI+ for VCL基础 -- 图像显示辅助类ImageAttributes
- GDI+最简单的代码,用于GDI+入门
- 实际开发中,实用的辅助iOS开发的工具
- 程序开发 很常用且实用的几个辅助软件
- 美味连连-QQ游戏辅助-简单实用的QQ游戏美味连连辅助(非外挂)
- 常见的辅助类
- 网络的辅助类
- Gdi+实用入门
- 最实用的Eclipse热键
- twitter最实用的应用
- eclipse最实用的手记
- linux最实用的命令
- VB 使用 Dir 函数遍历文件夹
- Joda-Time 简介
- android VelocityTracker类
- jQuery中的CheckBox、RadioButton、DropDownList的取值赋值
- Linux 2.6下Driver开发的34个变化[转贴]
- 最实用的GDI辅助类
- 基于Hadoop平台的并行数据挖掘算法工具-Dodo
- AsyncSocket发送数据错误
- 高通89系列的fastboot烧写顺序
- 批处理for命令详解
- jQuery下的ajax操作(SpringMVC3.0架构)
- Lucene简介&Lucene示例
- 深入浅出java 序列化概念
- log4j配置