1、建立基于对话框的MFC,工程名为test,在对话框添加button控件,并将button控件的Owner Draw的属性改为true;
2、添加一个子类CMyButton继承于CButton类;
3、在CtestDlg类中添加成员变量CMyButton m_MyButton,并在OnInitDialog中添加:
m_MyButton.SubclassDlgItem(IDC_BUTTON1,this); //这是将成员变量与具体控件相关联,并将CMyButton类的消息加入CtestDlg类的消息路由中
4、并在CMyButton中添加虚函数void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
5、详细的程序代码:
1 //控件重绘 2 void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 3 { 4 // TODO: 添加您的代码以绘制指定项 5 CBitmap bitmap1,bitmap2; 6 bitmap1.LoadBitmapW(IDB_BITMAP2); //将位图对象和资源ID相关联 7 bitmap2.LoadBitmapW(IDB_BITMAP3); //将位图对象和资源ID相关联 8 UINT CtlID=lpDrawItemStruct->CtlID; //得到ID号 9 10 //创建画笔,用来画按钮控件矩形 11 //CPen pen; 12 //pen.CreatePen(PS_SOLID,1,RGB(255,0,0)); 13 //CPen* pOldPen=(CPen*)pDC->SelectObject(pen); 14 //pDC->Rectangle(rect); 15 16 if(CtlID==IDC_BIGCIRCLEBTN) 17 { 18 CDC* dc=CDC::FromHandle(lpDrawItemStruct->hDC); 19 CRect rect=lpDrawItemStruct->rcItem; //控件的大小 20 UINT state=lpDrawItemStruct->itemState; //控件的状态,是否按下 21 if (state&ODS_SELECTED) 22 dc->DrawFrameControl(&rect,DFC_BUTTON,DFCS_BUTTONPUSH|DFCS_PUSHED); 23 else 24 dc->DrawFrameControl(&rect,DFC_BUTTON,DFCS_BUTTONPUSH); 25 Refresh(bitmap1,dc,rect); 26 27 CString str; 28 GetWindowText(str); //得到按钮控件上caption 29 if (!str.IsEmpty()) 30 { 31 CSize size=dc->GetTextExtent(str); //使用当前的字体来确定一行字符串的宽度和高度 32 CPoint central=CPoint(rect.Width()/2-size.cx/2,rect.Height()/2-size.cy/2); //确定文本输出的起始位置 33 dc->SetTextColor(RGB(255,0,0)); //设置输出文本的字体颜色 34 /* 35 TRANSPARENT表示字体的背景不会擦除,意思是说可以透过字体与字体或者字体本身的缝隙可以看到背景 36 OPAQUE则刚好相反 37 */ 38 //dc->SetBkColor(RGB(0,0,255)); 设置文字显示区域背景颜色 39 dc->SetBkMode(TRANSPARENT); //默认形式是OPAQUE 40 if(state&ODS_SELECTED) central.Offset(1,1); 41 if (state&ODS_DISABLED) 42 dc->DrawState(central,size,NULL,ODS_DISABLED,TRUE,0,(HBRUSH)NULL); 43 else 44 dc->TextOut(central.x,central.y,str); 45 dc->SetBkMode(OPAQUE); 46 } 47 } 48 if(CtlID==IDC_SMALLCIRCLEBTN) 49 { 50 CDC* dc=CDC::FromHandle(lpDrawItemStruct->hDC); 51 CRect rect=lpDrawItemStruct->rcItem; 52 UINT state=lpDrawItemStruct->itemState; 53 if (state&ODS_SELECTED) 54 dc->DrawFrameControl(&rect,DFC_BUTTON,DFCS_BUTTONPUSH|DFCS_PUSHED); 55 else 56 dc->DrawFrameControl(&rect,DFC_BUTTON,DFCS_BUTTONPUSH); 57 Refresh(bitmap2,dc,rect); 58 CString str; 59 GetWindowText(str); //得到按钮控件上caption 60 if (!str.IsEmpty()) 61 { 62 CSize size=dc->GetTextExtent(str); //使用当前的字体来确定一行字符串的宽度和高度 63 CPoint central=CPoint(rect.Width()/2-size.cx/2,rect.Height()/2-size.cy/2); //确定文本输出的起始位置 64 dc->SetTextColor(RGB(255,0,255)); //设置输出文本的字体颜色 65 /* 66 TRANSPARENT表示字体的背景不会擦除,意思是说可以透过字体与字体或者字体本身的缝隙可以看到背景 67 OPAQUE则刚好相反 68 */ 69 dc->SetBkMode(TRANSPARENT); //默认形式是OPAQUE 70 if(state&ODS_SELECTED) central.Offset(1,1); 71 if (state&ODS_DISABLED) 72 dc->DrawState(central,size,NULL,ODS_DISABLED,TRUE,0,(HBRUSH)NULL); 73 else 74 dc->TextOut(central.x,central.y,str); 75 dc->SetBkMode(OPAQUE); 76 } 77 } 78 } 79 80 // DDB双缓冲法(适用于设备相关图) 81 //bitmap是指导入的DDB的位图,CDC相关控件的相关描述表,rect是指控件的尺寸 82 /************************************************************************/ 83 /*注意这里的函数说明,如果CBitmap不加引用的话,会出现,只有指针才能调用 84 error C2248: “CObject::CObject”: 无法访问 private 成员(在“CObject”类中声明) 85 */ 86 /************************************************************************/ 87 void CMyButton::Refresh(CBitmap& bitmap, CDC* dc, CRect rect) 88 { 89 CDC MemDC,mdc; //声明内存描述表,创建一个会在内存只中画画的画家 90 mdc.CreateCompatibleDC(dc); //与显示器兼容的设备描述表 91 MemDC.CreateCompatibleDC(dc); //与显示器兼容的设备描述表 92 BITMAP bitmapdate; //位图的数据 93 bitmap.GetBitmap(&bitmapdate); //从位图对象中获取数据 94 /************************************************************************/ 95 /* 96 因为CreateCompatibleBitmap初始化了一个与pDC指定的设备上下文兼容的位图, 97 位图与指定的设备上下文具有相同的颜色位面数或相同的每个像素的位数。 98 你可以试一试,如果此处传入&MemDC,完啦完啦,画家怎么画,图上都是灰色的线条,郁闷死啦。 99 */ 100 /************************************************************************/ 101 mdc.SelectObject(&bitmap); //把要导入位图选入,相当于把画好的图放入内存中 102 CBitmap MemBitmap; //定义内存画布 103 MemBitmap.CreateCompatibleBitmap(dc,rect.Width(),rect.Height()); //确定画布的大小,要与显示控件相兼容的描述表 104 //画家选择画布 105 MemDC.SelectObject(&MemBitmap); 106 MemDC.FillSolidRect(rect,RGB(0,0,0)); //系统默认就是黑色 107 //MemDC.Rectangle(rect); //这是矩形区域覆盖意思,画边框直线不能用这个 108 //将mdc的画布复制到MemDC中 109 //StretchBlt带有一定的拉伸和缩短变换 110 MemDC.StretchBlt(0,0,rect.Width(),rect.Height(),&mdc,0,0,bitmapdate.bmWidth,bitmapdate.bmHeight,SRCCOPY); 111 //将MemDC中画好的画布复制到控件的画布上,这个函数按照1:1比例进行复制 112 dc->BitBlt(0,0,rect.Width(),rect.Height(),&MemDC,0,0,SRCCOPY); 113 //绘图完成后的清理 114 MemBitmap.DeleteObject(); 115 MemDC.DeleteDC(); 116 mdc.DeleteDC(); 117 }
6、结果示意图: