用Hook解决在VC++与C++Builder方面界面设计的一些问题
原创作者: cc
最近我们在开发一个项目的过程中,遇到一个问题,我想也是很多人曾经遇到过的问题:比如有的成员擅长于用Microsoft Visual C++进行开发工作,有的成员可能对于Borland C++ Builder 进行开发工作,两种编译器符合C++标准的程序不同,所以在C++语言本身有些不同,更麻烦的是进行界面方面的开发工作,它们的差别就更大了,VC的MFC消息机制,C++ Builder的VCL(不知对不对,这个俺不熟悉).因为我们要开发一个类似于XP中的资源管理器左边的用于”导航作用”的不错的界面,因为我们项目的界面大部分是用CB完成的,而这个东西好像不是那么容易做的呀,我对C++ Builder 不太熟悉,着实让人头疼的呀!下面的这张图片是我写的最终结果,只要稍加修改就可以在C++ Builder中使用,因为我用的是 : SDK+STL+C++,所以只要稍加修改,最主要的是我在这其中所使用的string ,必须改为AnsiString ,还有几个小地方改一下就行了.
无意之间我想到可以用Hook机制来实现我在VC中写的关于界面部分代码很容易的移植到CB中去,我知道CB中好像可以直接用MFC的代码,不过我想没有多少去做的呀!我的思想基于这种想法:
不管是VC++ 还是 C++ Builder 只要提供一个窗口的句柄就可以了, 上面的图上的那个是在一个static 的控件中, 而在C++ Builder中我用的Panel,效果还不错的哟!在程序启动以后,需要安装一个基于WH_GETMESSAGE 的钩子,同时传入一个需要”寄生”的窗口的句柄,还有一个父窗口的句柄,同时还有一个用户自定义的消息,例如:
#define WM_EXTENDUI_MESSAGE WM_USER+1
CWndHook::InstallHook(::GetDlgItem(m_hWnd,IDC_TEST),m_hWnd,WM_EXTENDUI_MESSAGE);
第三个参数是用于单击的时候发送消息通知父窗口.这时就可以了.当程序结束时,只要调用一下:
CWndHook::UninstallHook();
是不是很容易!用起来容易的东西,其实幕后有很多的工作需要做的了,下面是我的全部代码:
/************************************************************************
Module : WndHook.h
Purpose: When I need write some codes about user interface both working at VC++ and Borland C++
Builder well,I use the Hook mechanism instead of creating new ActiveX
control.Install a hook and then parasitize at other control such as
static control to draw ......It's a very good idea.
Date :
Author: Chengang
Last Modified :
History :
************************************************************************/
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
#ifndef __WNDHOOK__H
#define __WNDHOOK__H
#pragma once
//The state of ExtendUI item
#define EXT_UI_COLLPSED 0x01
#define EXT_UI_EXPANDED 0x02
#define EXT_UI_MOUSEHOVER 0x04
//The state of subItem
#define ITEM_NORMAL 0x01
#define ITEM_MOUSEHOVER 0x02
#define ITEM_CLICKED 0x04
//the background color.
#define GROUP_BKGND_COLOR RGB(214,223,247)
#define TOTAL_BKGND_COLOR RGB(111,139,222)
#define TEXT_COLOR RGB(33,93,198)
#define WIDTH(rect) (rect.right-rect.left)
#define HEIGHT(rect) (rect.bottom-rect.top)
#define BOUND_MARGIN 5
#define GROUP_MARGIN 8
#define ICON_WIDTH 16
#define ICON_HEIGHT 16
class CUIManager;
//////////////////////////////////////////////////////////////////////////
class CWndHook {
public:
//Install a Hook
static void InstallHook(HWND hWndHost,HWND hWndParent,UINT uMsg);
//Uninstall the hook
static void UninstallHook();
//Hook function
static LRESULT CALLBACK WindowHook(int code,WPARAM wParam,LPARAM lParam);
protected:
static HHOOK ms_hHook ;
static HWND ms_hWndHost ;
static CUIManager ms_uiMana;
};
//////////////////////////////////////////////////////////////////////////
class CUISubItem {
public:
UINT m_uBitmapID ; //the icon of this subitem
string m_strText ; //the text of this subitem
RECT m_rect ; //the rect of the subitem
UINT m_uState ; //the state of each item.
CUISubItem(string const&,UINT uBitID );
~CUISubItem();
public:
void Draw(HDC hDC,RECT const& rect) ; //draw this subItem .
void OnMouseMove(POINT const& pt);
BOOL OnLButtonDown(POINT const& pt);
};
//////////////////////////////////////////////////////////////////////////
class CUIGroup {
public :
string m_strCaption ; //the caption of the group item
vector<CUISubItem*> m_subItem ; //this group item can includ more than one subitem.
UINT m_uItemState ; //state of this group item
RECT m_rect;
protected:
void GradientFill(HDC hDC ,RECT const& rect);
public:
CUIGroup(string const& str,UINT uState =EXT_UI_EXPANDED);
~CUIGroup();
void Draw(HDC hDC,RECT const& rect) ;//first draw itself ,then draw each subitem .
int OnLButtonDown(POINT const& pt) ;
void OnMouseMove(POINT const& pt);
};
//////////////////////////////////////////////////////////////////////////
class CUIManager {
public:
vector<CUIGroup*> m_groupItem ; //UIManager manage all the group item.
RECT m_rectTotal ;//The region of this ExtendUI
HWND m_hWnd ; //parent hwnd ,used to post message
UINT m_uMessage ; //this message used to notify the parent window that
//which item wat clicked ,the wParam is the group NO
//the start index is 0 ,the lParam is the sub item index
//the start index also is 0.
CUIManager(){}
~CUIManager();
public:
void Draw(HDC hDC,RECT const& rect);
//add a new group
void AddGroup(string const&,UINT uState =EXT_UI_EXPANDED);
//add a new item to special group
void AddItem(int nGroupIndex,string const&,UINT);
void OnLButtonDown(POINT const& pt);
void OnMouseMove(POINT const& pt);
};
#endif //end of __WNDHOOK__H
/************************************************************************
Module : WndHook.cpp
Purpose: When I need write some codes both working at VC++ and Borland C++
Builder,I use the Hook mechanism instead of creating new ActiveX
control.Install a hook and then parasitize other control such as
static control to extend the function.It's a very good idea.
Date :
Author: Chengang
Last Modified :
History :
************************************************************************/
#include "..\StdAfx.h"
#include "..\Resource.h"
#include "WndHook.h"
#include "DCEx.h"
#include "draw.h"
//////////////////////////////////////////////////////////////////////////
HHOOK CWndHook::ms_hHook = NULL ;
HWND CWndHook::ms_hWndHost = NULL ;
CUIManager CWndHook::ms_uiMana;
//////////////////////////////////////////////////////////////////////////
void CWndHook::InstallHook(HWND hWndHost,HWND hWndParent,UINT uMsg) {
//if hWndHost or hWndParent is NULL,don't install this hook
if (NULL == hWndHost || NULL == hWndParent ||ms_hHook !=NULL)
return ;
ms_hWndHost = hWndHost;
//the user-defined message ,used to notify the parent window when a sub item was clicked.
ms_uiMana.m_uMessage = uMsg ;
ms_uiMana.m_hWnd = hWndParent;
string str="我的电脑";
ms_uiMana.AddGroup(str);
str="添加/删除程序";
ms_uiMana.AddGroup(str,EXT_UI_COLLPSED);
ms_uiMana.AddItem(0,string("控制面板"),IDB_MIDL);
ms_uiMana.AddItem(0,string("用户/帐户"),IDB_BAG);
ms_uiMana.AddItem(0,string("管理工具"),IDB_BUTTERFLY);
ms_uiMana.AddItem(1,string("控制面板"),IDB_CDAUDIO);
ms_uiMana.AddItem(1,string("用户/帐户"),IDB_MIDL );
ms_uiMana.AddItem(1,string("管理工具"),IDB_BUTTERFLY);
ms_uiMana.AddItem(1,string("控制面板"),IDB_CDAUDIO);
ms_uiMana.AddItem(1,string("控制面板"),IDB_CDAUDIO);
ms_uiMana.AddItem(1,string("用户/帐户"),IDB_MIDL );
ms_uiMana.AddItem(1,string("管理工具"),IDB_BUTTERFLY);
ms_uiMana.AddItem(1,string("控制面板"),IDB_CDAUDIO);
ms_uiMana.AddItem(1,string("用户/帐户"),IDB_MIDL );
ms_uiMana.AddItem(1,string("管理工具"),IDB_BUTTERFLY);
ms_uiMana.AddItem(1,string("控制面板"),IDB_MIDL);
ms_uiMana.AddItem(1,string("用户/帐户"),IDB_BAG);
ms_uiMana.AddItem(1,string("管理工具"),IDB_BUTTERFLY);
ms_hHook = ::SetWindowsHookEx(WH_GETMESSAGE,WindowHook,(HINSTANCE)::GetModuleHandle(NULL),::GetCurrentThreadId());
}
//////////////////////////////////////////////////////////////////////////
void CWndHook::UninstallHook() {
if (ms_hHook)
::UnhookWindowsHookEx(ms_hHook);
ms_hHook = NULL;
}
//////////////////////////////////////////////////////////////////////////
//Hook function
LRESULT CALLBACK CWndHook::WindowHook(int code,WPARAM wParam,LPARAM lParam) {
MSG *pMsg = (MSG*)lParam;
if (HC_ACTION == code ) {
if (::IsWindow(ms_hWndHost)){
RECT rectWindow ;
::GetWindowRect(ms_hWndHost,&rectWindow);
::MapWindowPoints(NULL,ms_hWndHost,(LPPOINT)&rectWindow,2);
POINT pt;
::GetCursorPos(&pt);
::ScreenToClient(ms_hWndHost,&pt);
if (WM_PAINT==pMsg->message||WM_MOUSEMOVE == pMsg->message && PtInRect(&rectWindow,pt) ||WM_LBUTTONDOWN == pMsg->message && PtInRect(&rectWindow,pt) ||WM_MOVE==pMsg->message||WM_NCACTIVATE==pMsg->message ||WM_NCPAINT==pMsg->message) {
HDC hDC = ::GetDC(ms_hWndHost);
CDCEx dc(hDC,rectWindow,TRUE,ms_hWndHost);
if (WM_LBUTTONDOWN == pMsg->message) {
ms_uiMana.OnLButtonDown(pt);
}
if (WM_MOUSEMOVE == pMsg->message) {
ms_uiMana.OnMouseMove(pt);
}
ms_uiMana.Draw(dc,rectWindow);
}
}
}
return ::CallNextHookEx(ms_hHook,code,wParam,lParam);
}
//////////////////////////////////////////////////////////////////////////
CUIGroup::CUIGroup(string const& str,UINT uState) {
m_uItemState = uState ;
m_strCaption = str;
}
//////////////////////////////////////////////////////////////////////////
CUIGroup::~CUIGroup() {
vector<CUISubItem*>::iterator iter = m_subItem.begin() ;
for ( ; iter != m_subItem.end() ; iter++) {
CUISubItem * pItem = *iter;
delete pItem;
}
m_subItem.clear();
}
//////////////////////////////////////////////////////////////////////////
void CUIGroup::Draw(HDC hDC,RECT const& rect) {
int nBkMode = ::SetBkMode(hDC,TRANSPARENT);
//draw the frame of this group
RECT rectText = rect;
RECT rectGrad =rect;
::DrawText(hDC,m_strCaption.c_str(),-1,&rectText,DT_CALCRECT);
int nHeight ,nWidth ;
nHeight = HEIGHT(rectText);
nWidth = WIDTH(rectText);
m_rect = rect;
m_rect.bottom = m_rect.top+nHeight+BOUND_MARGIN;
RECT rectRectangle = rect;
rectRectangle.top+=BOUND_MARGIN;
CBrushDCEx brush(hDC,GROUP_BKGND_COLOR);
CPenDCEx pen(hDC,RGB(255,255,255));
::RoundRect(hDC,rectRectangle.left,rectRectangle.top,rectRectangle.right,rectRectangle.bottom,5,5);
rectText = rect ;
::InflateRect(&rectText,-BOUND_MARGIN,-BOUND_MARGIN);
rectText.right = rectText.left+nWidth;
rectText.bottom = rectText.top+nHeight+BOUND_MARGIN;
rectGrad.bottom = rectGrad.top+nHeight+BOUND_MARGIN*2;
rectGrad.left = rect.left ;
rectGrad.right = rect.left+WIDTH(rect);
GradientFill(hDC,rectGrad);
HBITMAP hBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(m_uItemState&EXT_UI_EXPANDED?IDB_UP:IDB_DOWN));
BITMAP bm ;
GetObject(hBitmap,sizeof(BITMAP),&bm);
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC,hBitmap);
::BitBlt(hDC,rect.right-bm.bmWidth,rect.top,bm.bmWidth,bm.bmHeight,hMemDC,0,0,SRCCOPY);
SelectObject(hMemDC,hOldBitmap);
::DeleteDC(hMemDC);
::DeleteObject(hBitmap);
COLORREF clrTextColor = RGB(0,0,123);
if (m_uItemState & EXT_UI_MOUSEHOVER)
clrTextColor = MakeXPColor(clrTextColor,0.1);
int nOldTextColor = ::SetTextColor(hDC,clrTextColor);
::DrawText(hDC,m_strCaption.c_str(),-1,&rectText,DT_SINGLELINE|DT_VCENTER|DT_CENTER|DT_TOP);
::SetTextColor(hDC,nOldTextColor);
//draw each sub item
RECT rectSubItem =rectRectangle;
rectSubItem.top+=nHeight+BOUND_MARGIN*2;
rectSubItem.bottom =nHeight+BOUND_MARGIN;
if (m_uItemState & EXT_UI_EXPANDED) {
vector<CUISubItem*>::iterator iter = m_subItem.begin() ;
for (; iter != m_subItem.end(); iter++) {
CUISubItem* pItem = *iter ;
rectSubItem.bottom = rectSubItem.top+nHeight+BOUND_MARGIN;
pItem->Draw(hDC,rectSubItem);
rectSubItem.top +=nHeight+BOUND_MARGIN;
}
}
::SetBkMode(hDC,nBkMode);
}
//////////////////////////////////////////////////////////////////////////
//if clicked sub item in this group ,return the index of sub item ,else return
//-1,indicate not click at any subitem in this group
int CUIGroup::OnLButtonDown(POINT const& pt) {
int nReturn = -1;
if (PtInRect(&m_rect,pt)) {
if (m_uItemState & EXT_UI_EXPANDED)
m_uItemState = EXT_UI_COLLPSED;
else
m_uItemState = EXT_UI_EXPANDED;
} else {
vector<CUISubItem*>::iterator iter = m_subItem.begin() ;
for (int i= 0; iter != m_subItem.end(); iter++,i++) {
CUISubItem* pItem = *iter ;
if (pItem->OnLButtonDown(pt))
return i;
}
}
return nReturn;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CUISubItem::Draw(HDC hDC,RECT const& rect) {
//if text is null ,return
if (m_strText.empty()) return ;
//first draw the icon
HFONT hFont = NULL ,hOldFont = NULL;
if (m_uState & ITEM_CLICKED) {
//if this item was clicked ,draw the underline text ,so indicate
//this item was clicked.creae new font that with underlined propery
hFont = CreatePointSizeFont(hDC,8,string("Arial"),TRUE);
hOldFont = (HFONT)::SelectObject(hDC,hFont);
}
COLORREF clrText = TEXT_COLOR;
if (m_uState & ITEM_MOUSEHOVER) {
clrText = MakeXPColor(clrText,0.4);
}
int nOldTextColor = ::SetTextColor(hDC,clrText);
//draw the text
RECT rectText = rect;
rectText.left = rectText.left+BOUND_MARGIN*6;
::DrawText(hDC,m_strText.c_str(),-1,&rectText,DT_SINGLELINE|DT_VCENTER);
if (m_uBitmapID) {
DrawBitmap(hDC,m_uBitmapID,rect.left+BOUND_MARGIN,rect.top);
}
m_rect = rect ;
::SetTextColor(hDC,nOldTextColor);
if (hOldFont) ::SelectObject(hDC,hOldFont);
if (hFont) ::DeleteObject(hFont);
}
CUISubItem::CUISubItem(string const& str,UINT uBitmap) {
m_strText = str;
m_uBitmapID = uBitmap ;
m_uState = ITEM_NORMAL;
}
CUISubItem::~CUISubItem() {
}
void CUISubItem::OnMouseMove(POINT const& pt) {
if (PtInRect(&m_rect,pt)) {
HCURSOR hCursor = ::LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HAND));
::SetCursor(hCursor);
m_uState = ITEM_MOUSEHOVER;
}
else
m_uState = ITEM_NORMAL;
}
//////////////////////////////////////////////////////////////////////////
//if the mouse in this item 's rect return TRUE ,else return FALSE
BOOL CUISubItem::OnLButtonDown(POINT const& pt) {
if (PtInRect(&m_rect,pt)) {
m_uState |= ITEM_CLICKED;
return TRUE ;
} else {
m_uState = ITEM_NORMAL;
return FALSE ;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//Gradient fill
void CUIGroup::GradientFill(HDC hDC ,RECT const& rect){
BYTE byRed=255;
BYTE byGreen = 255;
BYTE byBlue = 255;
for (int x= rect.left,nStep=0;x<rect.right ;x++,nStep++) {
int nInc = 0 ;
if (nStep < 5)
nInc = nStep==1?3:(nStep==4?1:5-nStep);
else if (rect.right - x < 5)
nInc =rect.right-x==0?3:(rect.right-x==5?1:(rect.right-x==4?1:6-(rect.right-x)));
CPenDCEx dc(hDC,RGB(byRed,byGreen,byBlue));
::MoveToEx(hDC,x,rect.top+nInc,NULL);
::LineTo(hDC,x,rect.bottom);
if (0 == nStep%2)
byRed--;
if (0 == nStep %4)
byGreen--;
if (0 == nStep %5)
byBlue--;
}
}
void CUIGroup::OnMouseMove(POINT const& pt) {
if (PtInRect(&m_rect,pt)) {
m_uItemState |= EXT_UI_MOUSEHOVER;
HCURSOR hCursor = ::LoadCursor(GetModuleHandle(NULL),MAKEINTRESOURCE(IDC_HAND));
::SetCursor(hCursor);
}
else {
m_uItemState&=~EXT_UI_MOUSEHOVER;
}
vector<CUISubItem*>::iterator iter = m_subItem.begin() ;
for (; iter != m_subItem.end(); iter++) {
CUISubItem* pItem = *iter ;
pItem->OnMouseMove(pt);
}
}
void CUIManager::OnMouseMove(POINT const& pt) {
vector<CUIGroup*>::iterator it = m_groupItem.begin();
for (int i =0 ; it != m_groupItem.end() ; it++,i++ ) {
CUIGroup* pGroup ;
pGroup= *it;
pGroup->OnMouseMove(pt);
}
}
//////////////////////////////////////////////////////////////////////////
void CUIManager::Draw(HDC hDC,RECT const& rect) {
if (NULL == hDC) return ;
//draw the background color
HBRUSH hBrush = ::CreateSolidBrush(TOTAL_BKGND_COLOR);
::FillRect(hDC,&rect,hBrush);
::DeleteObject(hBrush);
if (m_groupItem.empty())
return ;
//calculate each region of each group
int nHeight = HEIGHT(rect) - 2*BOUND_MARGIN - (m_groupItem.size()>1?(m_groupItem.size()-1)*GROUP_MARGIN:0);
//if there was not enough space to drawing ,return
if (nHeight < 0)
return ;
int nEachHeight = nHeight/m_groupItem.size();
//draw each group item
vector<CUIGroup*>::iterator it = m_groupItem.begin();
RECT rectEach = rect;
rectEach.left = rect.left + BOUND_MARGIN;
rectEach.top = rect.top + BOUND_MARGIN;
rectEach.right -=BOUND_MARGIN;
string strFont="Arial";
HFONT hFont = CreatePointSizeFont(hDC,8,strFont,FALSE);
HFONT hOldFont = (HFONT)::SelectObject(hDC,hFont);
//calculate the height of each line
RECT rectText ;
::DrawText(hDC,"dummy",-1,&rectText,DT_CALCRECT);
for (int i =0 ; it != m_groupItem.end() ; it++,i++ ) {
CUIGroup* pGroup ;
pGroup= *it;
if (pGroup->m_uItemState & EXT_UI_EXPANDED)
rectEach.bottom = rectEach.top+((pGroup->m_subItem.size()+1)*(HEIGHT(rectText)+BOUND_MARGIN*2));
else
rectEach.bottom = rectEach.top+20;
pGroup->Draw(hDC,rectEach);
rectEach.top+=rectEach.bottom+GROUP_MARGIN*2;
}
::SelectObject(hDC,hOldFont);
::DeleteObject(hFont);
}
//////////////////////////////////////////////////////////////////////////
CUIManager::~CUIManager() {
vector<CUIGroup*>::iterator iter = m_groupItem.begin();
CUIGroup* pGroup = NULL;
while (iter != m_groupItem.end()) {
pGroup = *iter;
delete pGroup ;
iter++;
}
m_groupItem.clear() ;
}
//////////////////////////////////////////////////////////////////////////
//add a new group
void CUIManager::AddGroup(string const& str,UINT uState) {
CUIGroup* pGroup = new CUIGroup(str,uState);
m_groupItem.push_back(pGroup);
}
//////////////////////////////////////////////////////////////////////////
void CUIManager::AddItem(int nGroupIndex,string const& str,UINT uBitmap) {
if (nGroupIndex > m_groupItem.size()-1)
return ;
CUIGroup* pGroup = m_groupItem[nGroupIndex];
CUISubItem* pItem = new CUISubItem(str,uBitmap);
pGroup->m_subItem.push_back(pItem);
}
//////////////////////////////////////////////////////////////////////////
void CUIManager::OnLButtonDown(POINT const& pt) {
int nReturnValue = -1;
vector<CUIGroup*>::iterator it = m_groupItem.begin();
for (int i =0 ; it != m_groupItem.end() ; it++,i++ ) {
CUIGroup* pGroup ;
pGroup= *it;
nReturnValue = pGroup->OnLButtonDown(pt) ;
if (nReturnValue != -1){
::PostMessage(m_hWnd,m_uMessage,(WPARAM)i,(LPARAM)nReturnValue);
}
}
}
/************************************************************************
Module : draw.h
Provide many lesser class to convenient drawing.
Author: ChenGang
Date:
Last modified :
History :
1.
bitmap more conveience.
*************************************************************************/
#ifndef CLR_NONE
#define CLR_NONE 0xffffffffL
#endif
#pragma once
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class CPenDCEx
{
protected:
HPEN m_pen;
HDC m_hDC;
HPEN m_hOldPen;
int m_nWidth;
int m_nPenStyle;
public:
CPenDCEx (HDC hDC, COLORREF crColor = CLR_NONE,int nWidth =1,int nPenStyle = PS_SOLID)
{
m_hDC = hDC;
m_pen =CreatePen (nPenStyle, nWidth, crColor);
m_hOldPen = (HPEN)::SelectObject (m_hDC, m_pen);
m_nWidth = nWidth ;
m_nPenStyle = nPenStyle ;
}
~CPenDCEx ()
{
::SelectObject (m_hDC, m_hOldPen);
DeleteObject(m_pen);
}
void Color (COLORREF crColor,int nWidth)
{
::SelectObject (m_hDC, m_hOldPen);
DeleteObject(m_pen);
m_pen = CreatePen (m_nPenStyle, nWidth, crColor);
m_hOldPen = (HPEN)::SelectObject (m_hDC, m_pen);
}
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
class CBrushDCEx
{
protected:
HBRUSH m_brush;
HDC m_hDC;
HBRUSH m_hOldBrush;
public:
CBrushDCEx (HDC hDC, COLORREF crColor = CLR_NONE)
{
m_hDC = hDC;
if ( crColor == CLR_NONE ) m_brush =(HBRUSH) GetStockObject (NULL_BRUSH);
else m_brush =CreateSolidBrush (crColor);
m_hOldBrush = (HBRUSH)::SelectObject (m_hDC, m_brush);
}
~CBrushDCEx ()
{
::SelectObject (m_hDC, m_hOldBrush);
DeleteObject(m_brush);
}
void Color (COLORREF crColor) {
DeleteObject(m_brush);
if ( crColor == CLR_NONE ) m_brush = (HBRUSH)GetStockObject (NULL_BRUSH);
else m_brush = CreateSolidBrush (crColor);
m_hOldBrush = (HBRUSH)::SelectObject (m_hDC, m_brush);
::SelectObject (m_hDC, m_hOldBrush);
}
};
//////////////////////////////////////////////////////////////////////////
//Use the algorithm ,to calculate the color is very pretty.
COLORREF MakeXPColor(COLORREF cl, double factor)
{
if(factor>0.0&&factor<=1.0){
BYTE red,green,blue,lightred,lightgreen,lightblue;
red = GetRValue(cl);
green = GetGValue(cl);
blue = GetBValue(cl);
lightred = (BYTE)((factor*(255-red)) + red);
lightgreen = (BYTE)((factor*(255-green)) + green);
lightblue = (BYTE)((factor*(255-blue)) + blue);
cl = RGB(lightred,lightgreen,lightblue);
}
return(cl);
}
//////////////////////////////////////////////////////////////////////////
HFONT CreatePointSizeFont(HDC hDC, short shFontSize,string strFontFacename,BOOL fUnderline)
{
HFONT hFont;
LOGFONT lf;
ZeroMemory(&lf,sizeof(LOGFONT));
lf.lfUnderline = fUnderline ;
lf.lfHeight = -MulDiv(shFontSize,GetDeviceCaps(hDC,LOGPIXELSY),72);
strcpy(lf.lfFaceName,strFontFacename.c_str());
hFont = CreateFontIndirect(&lf) ;
return hFont;
}
//////////////////////////////////////////////////////////////////////////
void DrawBitmap(HDC hDC ,UINT nResID,int x ,int y ) {
HBITMAP hBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(nResID));
BITMAP bm ;
GetObject(hBitmap,sizeof(BITMAP),&bm);
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC,hBitmap);
::BitBlt(hDC,x,y,bm.bmWidth,bm.bmHeight,hMemDC,0,0,SRCCOPY);
::SelectObject(hMemDC,hOldBitmap);
::DeleteDC(hMemDC);
::DeleteObject(hBitmap);
}
/*****************************************************************************/
/* */
/* FileName :DCEx.h */
/* */
/* Purpose : By the famous CMemDC ,I desien CDCEx as a win32 version instead */
/* of CMemDC (By MFC).Use the double buffer technology,to increase the */
/* velocity of drawing. */
/* */
/* Author : ChenGang */
/* Date : 2/16/2005 */
/* */
/* Last Modified : 2/16/2005 */
/*****************************************************************************/
class CDCEx
{
private:
HBITMAP m_hBitmap;
HBITMAP m_hOldBitmap;
HDC m_hDC ;
HDC m_hOldDC;
RECT m_rect;
BOOL m_bNeedRelease ;
HWND m_hWndNeedRelease;
public:
CDCEx(HDC hDC ,const RECT rect,BOOL bNeedRelease=FALSE,HWND hWndNeedRelease=NULL)
{
// ATLASSERT(hDC != NULL) ;
m_hOldDC = hDC;
m_bNeedRelease = bNeedRelease ;
m_hWndNeedRelease = hWndNeedRelease;
m_rect = rect;
m_hDC = CreateCompatibleDC(hDC);
LPtoDP(hDC,(LPPOINT)&m_rect,2);
m_hBitmap = CreateCompatibleBitmap(hDC,m_rect.right - m_rect.left ,m_rect.bottom - m_rect.top);
m_hOldBitmap = (HBITMAP)SelectObject(m_hDC,m_hBitmap);
SetMapMode(m_hDC,GetMapMode(m_hOldDC));
SIZE size;
GetWindowExtEx(hDC,&size);
SetWindowExtEx(m_hDC,size.cx,size.cy,NULL);
GetViewportExtEx(hDC,&size);
SetViewportExtEx(m_hDC,size.cx,size.cy,NULL);
DPtoLP(hDC,(LPPOINT)&m_rect,2);
SetWindowOrgEx(m_hDC,m_rect.left,m_rect.top,NULL);
//First fill whole background rect.
HBRUSH hBrush =CreateSolidBrush(GetBkColor(hDC));
FillRect(m_hDC,&m_rect,hBrush);
DeleteObject(hBrush);
}
~CDCEx()
{
BitBlt(m_hOldDC,m_rect.left,m_rect.top,m_rect.right - m_rect.left,m_rect.bottom - m_rect.top,m_hDC,m_rect.left,m_rect.top,SRCCOPY);
SelectObject(m_hDC,m_hOldBitmap);
if (m_hBitmap)
DeleteObject(m_hBitmap);
DeleteDC(m_hDC);
if (m_bNeedRelease)
::ReleaseDC(m_hWndNeedRelease,m_hOldDC);
m_hDC = NULL;
m_hBitmap = NULL;
m_hOldBitmap = NULL;
}
operator HDC()
{
return m_hDC ;
}
};
这种想法希望能起到抛砖引玉的作用,不要砸到自己..........
以上就是全部的代码,如果有什么不清楚或者有指教的地方,可以给我E-mail:[email protected].