发现QQ的左侧的工具栏挺酷的,今天自己模仿了一个.直接用的QQ的图片资源文件.
开始的时候呢,想用N个按钮来组合成那样的工具栏,但是发现显示的层次总是控制不好.比如当鼠标在第二个按钮上时,它竟然把上面的按钮盖住了一部分,很难看.
后来索性把它们弄成一个按钮,通过鼠标所在的位置来判断所按的"按钮"(并非真正的按钮),并通过自己添加的BindMessage函数来为每个"按钮"来"绑定"一个消息.比如为第一个"按钮"绑定WM_MY_MESSAGE,这样就可以在主窗口中用ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage)来处理了.
添加一个按钮也很简单InsertButton(LPSTR szIcon),参数是按钮图标的文件名.
完整代码如下:
//XToolbar.h
struct BitmapInfo
{
BOOL bHover;
BOOL bPushed;
HBITMAP hBitmapNormal;
HBITMAP hBitmapHover;
HBITMAP hBitmapPush;
HICON hIcon;
BitmapInfo * pNext;
};
class CXToolbar : public CButton
{
DECLARE_DYNAMIC(CXToolbar)
public:
CXToolbar();
virtual ~CXToolbar();
virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
BOOL InsertButton(LPSTR szIcon);
BOOL SetCursor(HCURSOR hCursor);
BOOL BindMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
BOOL Create(CWnd * pParentWnd, UINT nID,int x, int y, LPCTSTR szIocn);
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
private:
UINT m_uTypeStyle;
BOOL m_bCheckBox;
HCURSOR m_hCursor;
BOOL m_bTracking;
HRGN m_hRgn;
COLORREF m_clrTransparent;
int m_nWidth;
int m_nHeight;
BitmapInfo * m_pbiHead;
BitmapInfo * m_pbiTail;
UINT m_uMessage;
WPARAM m_wParam;
LPARAM m_lParam;
};
//XToolbar.cpp
#include "XToolbar.h"
BOOL TransBlt(HDC hdcDest,int nXDest,int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc,COLORREF crColour)
{
COLORREF crOldBack = SetBkColor(hdcDest,RGB(255,255,255));
COLORREF crOldText = SetTextColor(hdcDest,0);
HDC dcTrans;
dcTrans = CreateCompatibleDC(hdcDest);
HBITMAP bitmapTrans;
bitmapTrans = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
HBITMAP OldBitmapTrans = (HBITMAP)SelectObject(dcTrans,bitmapTrans);
COLORREF crOldBackSrc = SetBkColor(hdcSrc,crColour);
BitBlt(dcTrans,0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
BitBlt(hdcDest,nXDest, nYDest, nWidth, nHeight, hdcSrc, 0, 0, SRCINVERT);
BitBlt(hdcDest,nXDest, nYDest, nWidth, nHeight, dcTrans, 0, 0, SRCAND);
BitBlt(hdcDest,nXDest, nYDest, nWidth, nHeight, hdcSrc, 0, 0, SRCINVERT);
SelectObject(dcTrans,OldBitmapTrans);
DeleteDC(dcTrans);
DeleteObject(bitmapTrans);
SetBkColor(hdcDest,crOldBack);
SetBkColor(hdcSrc,crOldBackSrc);
SetTextColor(hdcDest,crOldText);
return TRUE;
}
HBITMAP LoadBitmapFromFile(LPCTSTR szBitmapName)
{
return (HBITMAP)LoadImage(NULL, szBitmapName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
HICON LoadIconFromFile(LPCTSTR szIconName)
{
return (HICON)LoadImage(NULL, szIconName, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
}
IMPLEMENT_DYNAMIC(CXToolbar, CButton)
CXToolbar::CXToolbar()
{
m_hCursor = NULL;
m_bCheckBox = FALSE;
m_uTypeStyle = BS_TYPEMASK; //???
m_bTracking = FALSE;
m_clrTransparent = RGB(255,0,255);
m_hRgn = NULL;
m_nWidth = 27;
m_nHeight = 37;
m_uMessage = 0;
m_wParam = 0;
m_lParam = 0;
m_pbiHead = new BitmapInfo;
m_pbiHead->hBitmapNormal = LoadBitmapFromFile("Skin//4.bmp");
m_pbiHead->hBitmapHover = LoadBitmapFromFile("Skin//5.bmp");
m_pbiHead->hBitmapPush = LoadBitmapFromFile("Skin//3.bmp");
m_pbiHead->bPushed = TRUE;
m_pbiHead->bHover = FALSE;
m_pbiHead->pNext = NULL;
m_pbiTail = m_pbiHead;
}
CXToolbar::~CXToolbar()
{
while(m_pbiHead)
{
BitmapInfo * pTemp = m_pbiHead;
m_pbiHead = m_pbiHead->pNext;
if(pTemp->hBitmapNormal)
DeleteObject(pTemp->hBitmapNormal);
if(pTemp->hBitmapHover)
DeleteObject(pTemp->hBitmapHover);
if(pTemp->hBitmapPush)
DeleteObject(pTemp->hBitmapPush);
delete pTemp;
}
}
BEGIN_MESSAGE_MAP(CXToolbar, CButton)
ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_SETCURSOR()
END_MESSAGE_MAP()
void CXToolbar::PreSubclassWindow()
{
UINT nBS;
nBS = GetButtonStyle();
if (nBS & BS_CHECKBOX) m_bCheckBox = TRUE;
if (m_uTypeStyle == BS_DEFPUSHBUTTON)
m_uTypeStyle = BS_PUSHBUTTON;
ASSERT(m_uTypeStyle != BS_OWNERDRAW);
ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);
SetWindowPos(NULL,0,0,m_nWidth,m_nHeight,SWP_NOMOVE | SWP_NOZORDER);
CButton::PreSubclassWindow();
}
void CXToolbar::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC * pDC = CDC::FromHandle(lpDIS->hDC);
CDC * pMemDC = new CDC;
pMemDC->CreateCompatibleDC(pDC);
CBitmap * pOldBitmap = NULL;
BitmapInfo * pTemp = m_pbiHead;
int y = 0;
while(pTemp)
{
if(pTemp->bPushed)
pOldBitmap = (CBitmap*)pMemDC->SelectObject(CBitmap::FromHandle(pTemp->hBitmapPush));
else if(pTemp->bHover)
pOldBitmap = (CBitmap*)pMemDC->SelectObject(CBitmap::FromHandle(pTemp->hBitmapHover));
else
pOldBitmap = (CBitmap*)pMemDC->SelectObject(CBitmap::FromHandle(pTemp->hBitmapNormal));
TransBlt(pDC->GetSafeHdc(),0,y,27,37,pMemDC->GetSafeHdc(),0,0,RGB(255,0,255));
if(pTemp->hIcon)
DrawIconEx(pDC->GetSafeHdc(), 3, 3 + y, pTemp->hIcon,24,24,NULL,NULL,DI_NORMAL);
pMemDC->SelectObject(pOldBitmap);
y += 33;
pTemp = pTemp->pNext;
}
delete pMemDC;
}
LRESULT CXToolbar::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
m_bTracking = FALSE;
BitmapInfo * pTemp = m_pbiHead;
while(pTemp)
{
pTemp->bHover = FALSE;
pTemp = pTemp->pNext;
}
Invalidate(0);
return 0;
}
LRESULT CXToolbar::OnMouseHover(WPARAM wParam, LPARAM lParam)
{
return 0;
}
void CXToolbar::OnMouseMove(UINT nFlags, CPoint point)
{
BOOL bRedraw = FALSE;
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bTracking = _TrackMouseEvent(&tme);
}
CRect rect;
rect.left = 0;
rect.right = 26;
int i = 0;
BitmapInfo * pTemp = m_pbiHead;
while(pTemp)
{
rect.top = i * 33;
rect.bottom = i * 33 + 32;
if(rect.PtInRect(point))
{
if(!pTemp->bHover)
{
pTemp->bHover = TRUE;
bRedraw = TRUE;
}
}
else
{
if(pTemp->bHover)
{
pTemp->bHover = FALSE;
bRedraw = TRUE;
}
}
pTemp = pTemp->pNext;
i++;
}
if(bRedraw)
Invalidate(0);
TRACE("bRedraw = %d/n",bRedraw);
CButton::OnMouseMove(nFlags, point);
}
void CXToolbar::OnLButtonUp(UINT nFlags, CPoint point)
{
BOOL bRedraw = FALSE;
CRect rect;
rect.left = 0;
rect.right = 26;
int i = 0;
BitmapInfo * pTemp = m_pbiHead;
while(pTemp)
{
rect.top = i * 33;
rect.bottom = i * 33 + 32;
if(rect.PtInRect(point))
{
if(!pTemp->bPushed)
{
pTemp->bPushed = TRUE;
bRedraw = TRUE;
if(m_wParam == 0 && m_lParam == 0)
GetParent()->PostMessage(m_uMessage,0,(LPARAM)i);
else
GetParent()->PostMessage(m_uMessage,m_wParam,m_lParam);
}
}
else
{
if(pTemp->bPushed)
{
pTemp->bPushed = FALSE;
bRedraw = TRUE;
}
}
pTemp = pTemp->pNext;
i++;
}
if(bRedraw)
Invalidate(0);
CButton::OnLButtonUp(nFlags, point);
}
BOOL CXToolbar::InsertButton(LPSTR szIcon)
{
BitmapInfo * pTemp = new BitmapInfo;
pTemp->hBitmapNormal = LoadBitmapFromFile("Skin//barback2_normal.bmp");
pTemp->hBitmapHover = LoadBitmapFromFile("Skin//barback2_over.bmp");
pTemp->hBitmapPush = LoadBitmapFromFile("Skin//barback_disabled.bmp");
pTemp->hIcon = LoadIconFromFile(szIcon);
pTemp->bPushed = FALSE;
pTemp->bHover = FALSE;
pTemp->pNext = NULL;
m_pbiTail->pNext = pTemp;
m_pbiTail = pTemp;
m_nHeight += 33;
SetWindowPos(NULL,0,0,m_nWidth,m_nHeight,SWP_NOMOVE | SWP_NOZORDER);
return 0;
}
BOOL CXToolbar::SetCursor(HCURSOR hCursor)
{
m_hCursor = hCursor;
return TRUE;
}
BOOL CXToolbar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if(m_hCursor)
{
::SetCursor(m_hCursor);
return 1;
}
return CButton::OnSetCursor(pWnd, nHitTest, message);
}
BOOL CXToolbar::BindMessage(UINT message, WPARAM wParam , LPARAM lParam )
{
if(message <= 0)
return FALSE;
m_uMessage = message;
m_wParam = wParam;
m_lParam = lParam;
return TRUE;
}
BOOL CXToolbar::Create(CWnd * pParentWnd, UINT nID,int x, int y, LPCTSTR szIocn)
{
RECT rect;
rect.left = x; rect.right = x + 1; rect.top = y; rect.bottom = y + 1;
CButton::Create("", WS_CHILD | WS_VISIBLE, rect, pParentWnd, nID);
m_pbiHead->hIcon = LoadIconFromFile(szIocn);
return TRUE;
}
使用方法:
m_tb = new CXToolbar; //m_tb 的类型是 CXToolbar *
m_tb->Create(this, 8888,10,10,"Skin//FriendButton.ico"); //8888是它的ID
m_tb->InsertButton("Skin//CustomButton.ico");
m_tb->InsertButton("Skin//EaseButton.ico");
m_tb->InsertButton("Skin//SBuddyButton.ico");
m_tb->SetCursor(LoadCursor(NULL,MAKEINTRESOURCE(32649)));
m_tb->BindMessage(WM_MY_MESSAGE);