wince控件之从绘按钮(支持多种状态的图像加载、可通过图像创建不规程按钮)
没有控件库,是种痛苦;用wince上现成的控件,更是种痛苦。能显示图片的按钮有木有?!木有。菜单能不能支持图标?不能!列表能不能漂亮点?咋就这样,爱用不用!想换个平台,没办法!公司指定非用wince不可,就是不愿跟上技术的步法,只能看着其他的公司happy的进行着ios,android的开发。程序猿(媛)们怎么办?
这也算是本人的痛苦经历了,怎么办?只能自绘呗!这次先说说自绘按钮的事吧。最终的效果如下图所示,其中左边的按钮是能够显示多种状态的图像,而右边的按钮是通过图像创建了圆形的形状,同时也能够显示多种状态的图像。此外图像和文字的对齐方式也是可以设置的。
实现步骤
首先需要从CButton派生一个子类,比如CImageButton。然后实现自绘,必须通知按钮“hi,你不要绘制了,这交给我了”!,这可以通过覆盖父类的虚函数PreSubclassWindow,在其实现体中调用ModifyStyle函数来通知。具体参见下面的代码。
void CImageButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
// add owner draw styles
ModifyStyle(0, BS_OWNERDRAW);
}
之后,每次需要绘制按钮的时候,都会调用虚函数virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct),因而所有的绘制工作都需要放在这个函数的实现当中,这也是实现自绘按钮的主要工作所在,必须根据按钮的当前状态、大小、对齐方式、文字和图像大小等等来绘制。
自绘细节
- 从DrawItem的参数lpDrawItemStruct获取按钮状态、大小、绘图句柄。
- 根据按钮的状态,选择合适的图像以及调整绘制区域。
- 根据按钮的状态,绘制按钮的形状以及图像。
- 根据按钮的状态,绘制文字。
void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT(lpDrawItemStruct != NULL);// must have at least the first bitmap loaded before calling DrawItemASSERT(m_bitmapNorm.m_hObject != NULL); // required//Get button stateBOOL isFocus = lpDrawItemStruct->itemState & ODS_FOCUS;BOOL isPush = lpDrawItemStruct->itemState & ODS_SELECTED;if (m_hMenu && m_isMenuDisplayed){
isPush = TRUE;
}BOOL isDisable = lpDrawItemStruct->itemState & ODS_DISABLED;//Get button rectCRect btnRect(lpDrawItemStruct->rcItem);CRect frameControlRect(btnRect);int drawOffSet = 0;// get GDI resource: font,CDC,bitmap...CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);CBitmap* pBitmap = &m_bitmapNorm;if (isDisable){
if (m_bitmapDisabled.m_hObject != NULL){
pBitmap = &m_bitmapDisabled;
}
}if (isPush){
if (m_bitmapSel.m_hObject != NULL){
pBitmap = &m_bitmapSel;
}
if (!m_isCreateRgnFromBitmap){
drawOffSet = 1;
}
}else if (isFocus){
if (m_bitmapFocus.m_hObject != NULL){
pBitmap = &m_bitmapFocus;
}frameControlRect.DeflateRect(1,1);
}// if don't use bitmap as rgn and disable, draw button face and frame rectif (!m_isCreateRgnFromBitmap && !isDisable){
// fill button face with default system button face colorpDC->FillRect( btnRect , &CBrush( GetSysColor( COLOR_BTNFACE ) ) );if (!isPush){
pDC->DrawFrameControl(frameControlRect,DFC_BUTTON,DFCS_BUTTONPUSH);
}pDC->FrameRect(btnRect,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
}
// when button is disabled, if have not disable image,just fill image rect like text.// otherwise, use disabled image to fill this rectif (isDisable && m_bitmapDisabled.m_hObject == NULL){
CRect imageRect(m_imageRect);imageRect.OffsetRect(1,1);pDC->FillRect(imageRect,&CBrush(GetSysColor(COLOR_WINDOW)));imageRect.OffsetRect(-1,-1);pDC->FillRect(imageRect,&CBrush(GetSysColor(COLOR_GRAYTEXT)));
}else{
CDC memDC;memDC.CreateCompatibleDC(pDC);CBitmap* pOld = memDC.SelectObject(pBitmap);if (pOld == NULL)
return;
CRect imageRect(m_imageRect);imageRect.OffsetRect(drawOffSet,0);pDC->BitBlt(imageRect.left, imageRect.top, imageRect.Width(), imageRect.Height(),&memDC, 0, 0, SRCCOPY);memDC.SelectObject(pOld);memDC.DeleteDC();
}
CString text;GetWindowText(text);if (!text.IsEmpty()){
if (isDisable){
CRect textRect(m_textRect);textRect.OffsetRect(1,1);pDC->SetTextColor(GetSysColor(COLOR_WINDOW));int oldMode = pDC->SetBkMode(TRANSPARENT);CFont* pOldFont = pDC->SelectObject(GetTextFont());pDC->DrawText(text,textRect,DT_WORDBREAK| DT_CENTER|DT_VCENTER);textRect.OffsetRect(-1,-1);pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));pDC->DrawText(text,textRect,DT_WORDBREAK | DT_CENTER|DT_VCENTER);if (pOldFont){pDC->SelectObject(pOldFont);}pDC->SetBkMode(oldMode);
}else{
CRect textRect(m_textRect);textRect.OffsetRect(drawOffSet,0);pDC->SetTextColor(m_textColor);int oldMode = pDC->SetBkMode(TRANSPARENT);CFont* pOldFont = pDC->SelectObject(GetTextFont());pDC->DrawText(text,textRect,DT_WORDBREAK | DT_CENTER|DT_VCENTER);if (pOldFont){pDC->SelectObject(pOldFont);}pDC->SetBkMode(oldMode);
}
}if (!isDisable && isFocus && !m_isCreateRgnFromBitmap){
CRect focusRect(btnRect);focusRect.DeflateRect(2,2);focusRect.OffsetRect(drawOffSet,0);pDC->DrawFocusRect(focusRect);
}
}
这当中有几个函数比较不常见,DrawFrameControl、FrameRect、DrawFocusRect,调整相应的参数就可以看出其绘制的内容了。
依据文字长度和图片大小自动调整按钮大小(SizeToContent)
GetWindowText(text);
textRect.SetRectEmpty();
if (!text.IsEmpty())
{
CDC* pDC = GetDC();
if (pDC)
{
CFont* pOldFont = pDC->SelectObject(GetTextFont());
pDC->DrawText(text,&textRect,DT_CALCRECT|DT_WORDBREAK);
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
}
}
创建不规则按钮是通过掩码图片和颜色计算得出按钮的不规则区域,然后用新的区域来设置按钮的窗口区域及clip区域,详见下面的示例:
m_hClipRgn = CreateRgnFromBitmap(m_bitmapMask,RGB(255,255,255)); if (m_hClipRgn) { SetWindowRgn(m_hClipRgn,TRUE); CDC* pDC = GetDC(); if (pDC) { SelectClipRgn(pDC->GetSafeHdc(),m_hClipRgn); ReleaseDC(pDC); } }
如何使用
// 图片按钮 m_imageButton.LoadBitmaps(IDB_INFO_BITMAP,IDB_INFO_PUSH_BITMAP,IDB_INFO_FOCUS_BITMAP); m_imageButton.SetAlignStyle(AS_IMAGE_LEFT_TEXT_RIGHT); m_imageButton.SizeToContent(); m_skinBtn.SizeToContent(); // 不规则按钮m_skinBtn.LoadBitmaps(IDB_CIRCLE_NORM_BITMAP,IDB_CIRCLE_DOWN_BITMAP,IDB_CIRCLE_FOCUS_BITMAP,IDB_CIRCLE_DISABLE_BITMAP,IDB_CIRCLE_MASK_BITMAP); m_skinBtn.SizeToContent();
源文件下载地址:
http://download.****.net/detail/ryanzll/4518230