导航:[首页]->[wtl]->[在标题栏添加控件实现]
class NcWidgetBase{
public:
virtual void OnCreate(CWindow* window){}
virtual void OnDestroy(CWindow* window){}
virtual void OnPaint(CWindow* window,CWindowDC* dc){}
virtual void OnMouseMove(CWindow* window,const CPoint& point){}
virtual void OnMouseEnter(CWindow* window,const CPoint& point){}
virtual void OnMouseLeave(CWindow* window){}
virtual void OnLButtonDown(CWindow* window,const CPoint& point){}
virtual void OnLButtonDblClk(CWindow* window,const CPoint& point){}
virtual void OnLButtonUp(CWindow* window,const CPoint& point){}
// 返回true表示接收消息
virtual bool OnHitTest(const CPoint& point){return true;}
/////////////////////////////////////////////////////
// wrapper
/////////////////////////////////////////////////////
// OnHitTest
bool OnNcHitTestBase(const CPoint& point,CPoint* actual){
ATLASSERT(actual);
if(TRUE == this->m_position_.PtInRect(point)){
ATLASSERT(!m_position_.IsRectNull());
*actual = point;
// 将父窗口坐标改成当前窗口坐标
actual->Offset(-m_position_.TopLeft());
return this->OnHitTest(*actual);
}else
return false;
}
// OnPaint
void OnPaintBase(CWindow* window,CWindowDC* dc){
ATLASSERT(window);
ATLASSERT(dc);
// 创建客户区的rgn
CRgn rgn_;
rgn_.CreateRectRgnIndirect(m_position_);
dc->SelectClipRgn(rgn_, RGN_AND);
/*
MyDbgStr(_T("OnPaintBase %d,%d,%d,%d\n"),
m_position_.left,
m_position_.right,
m_position_.top,
m_position_.bottom);
*/
CPoint point_;
dc->SetViewportOrg(m_position_.TopLeft(),&point_);
this->OnPaint(window,dc);
dc->SetViewportOrg(point_);
}
/////////////////////////////////////////////////////
// util
/////////////////////////////////////////////////////
// 重绘
void RePaint(CWindow* window){
ATLASSERT(window);
window->SendMessage(WM_NCPAINT,0,0);
}
// layout,设置窗口位置
void LayoutWindow(const CRect& rect){
if(!this->m_position_.EqualRect(rect)){
this->m_position_ = rect;
}
}
// 将widget坐标转换为全局坐标
void PointToGlobal(CWindow* window,CPoint* point){
ATLASSERT(window);
ATLASSERT(point);
ATLASSERT(!m_position_.IsRectNull());
point->Offset(m_position_.TopLeft());
// 屏幕坐标转换成窗口坐标
CRect rcWindow;
window->GetWindowRect(rcWindow);
point->Offset(rcWindow.TopLeft());
}
private:
CRect m_position_;
};
template <class T,bool OWNER_DRAW>
class TitleWidget{
public:
typedef NcWidgetBase* Entry;
typedef std::vector<Entry> Vector;
typedef Vector::iterator Iter;
typedef Vector::reverse_iterator RIter;
public:
TitleWidget():
m_move_hittest_(NULL),
m_lbtn_hittest_(NULL),
m_mouse_tracking_(false){}
BEGIN_MSG_MAP(TitleWidget)
MESSAGE_HANDLER(WM_NCDESTROY, OnNcDestroy)
//MESSAGE_HANDLER(WM_NCCALCSIZE,OnNcCalcSize)
MESSAGE_HANDLER(WM_NCACTIVATE, OnNcPaint)
MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNcMouseMove)
MESSAGE_HANDLER(WM_NCMOUSELEAVE, OnNcMouseLeave)
MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)
MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblclk)
MESSAGE_HANDLER(WM_NCLBUTTONUP, OnNcLButtonUp)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
END_MSG_MAP()
/*
LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
bHandled = FALSE;
NCCALCSIZE_PARAMS* pParams = NULL;
RECT* pRect = NULL;
BOOL bValue = static_cast<BOOL>(wParam);
if(bValue)
pParams = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
else
pRect = reinterpret_cast<RECT*>(lParam);
if(bValue){
pRect = &pParams->rgrc[0];
}
pRect->left = pRect->left + 0;
pRect->top = pRect->top + 0;
pRect->right = pRect->right + 0;
pRect->bottom = pRect->bottom + 0;
MyDbgStr(_T("OnNcCalcSize %d,%d,%d,%d\n"),
pRect->left,
pRect->right,
pRect->top,
pRect->bottom);
if(bValue)
pParams->rgrc[1] = pParams->rgrc[0];
return TRUE;
}
*/
LRESULT OnNcDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = FALSE;
T* pT = static_cast<T*>(this);
for(RIter iter_ = m_widgets_.rbegin();
iter_ != m_widgets_.rend();
++ iter_){
//调用子控件destroy函数
ATLASSERT(*iter_);
(*iter_)->OnDestroy(pT);
}
return TRUE;
}
LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
//bHandled = FALSE;
T* pT = static_cast<T*>(this);
if(OWNER_DRAW)
;
else
::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam);
CRgn rgn;
{
CRect rcWindow, rcClient;
pT->GetWindowRect(rcWindow);
// layout
pT->OnNcLayout(pT,(UINT)wParam,rcWindow.Size());
pT->GetClientRect(rcClient);
pT->ClientToScreen(rcClient);
rcClient.OffsetRect(-rcWindow.TopLeft());
rcWindow.OffsetRect(-rcWindow.TopLeft());
// 创建整个窗口的rgn
rgn.CreateRectRgn(rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
// 创建客户区的rgn
CRgn clt_rgn_;
clt_rgn_.CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
// 排除客户区的rgn
rgn.CombineRgn(clt_rgn_,RGN_DIFF);
}
// 依次绘制子窗口
CWindowDC dc(pT->m_hWnd);
for(Iter iter_ = m_widgets_.begin();
iter_ != m_widgets_.end();
++ iter_){
dc.SelectRgn(rgn);
(*iter_)->OnPaintBase(pT,&dc);
}
dc.SelectRgn(rgn);
return TRUE;
}
LRESULT OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
if(!m_mouse_tracking_){
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE | TME_NONCLIENT; //注册非客户区离开
tme.hwndTrack = pT->m_hWnd;
tme.dwHoverTime = HOVER_DEFAULT; //只对HOVER有效
::TrackMouseEvent(&tme);
m_mouse_tracking_ = true;
}
CPoint point_;
GetPosition(&point_,lParam);
// 依次处理每一个widget
CPoint widget_point_;
for(RIter iter_ = m_widgets_.rbegin();
iter_ != m_widgets_.rend();
++ iter_){
if((*iter_)->OnNcHitTestBase(point_,&widget_point_)){
if(*iter_ != m_move_hittest_){
// 如果老widget存在,则发送OnMouseLeave
if(m_move_hittest_){
m_move_hittest_->OnMouseLeave(pT);
m_move_hittest_ = NULL;
}
// 如果是新widget,则发送MouseEnter
(*iter_)->OnMouseEnter(pT,widget_point_);
m_move_hittest_ = *iter_;
}
(*iter_)->OnMouseMove(pT,widget_point_);
return TRUE;
}
}
// 如果老widget存在,则发送OnMouseLeave
if(m_move_hittest_){
m_move_hittest_->OnMouseLeave(pT);
m_move_hittest_ = NULL;
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
LRESULT OnNcMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
m_mouse_tracking_ = false;
// 如果老widget存在,则发送OnMouseLeave
if(m_move_hittest_){
m_move_hittest_->OnMouseLeave(pT);
m_move_hittest_ = NULL;
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
LRESULT OnNcLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
CPoint point_;
GetPosition(&point_,lParam);
// 依次处理每一个widget
CPoint widget_point_;
for(RIter iter_ = m_widgets_.rbegin();
iter_ != m_widgets_.rend();
++ iter_){
if((*iter_)->OnNcHitTestBase(point_,&widget_point_)){
this->NotifyLButtonDown(*iter_,pT,widget_point_);
return TRUE;
}
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
void NotifyLButtonDown(NcWidgetBase* hittest,CWindow* window,const CPoint& point){
ATLASSERT(hittest);
ATLASSERT(window);
hittest->OnLButtonDown(window,point);
m_lbtn_hittest_ = hittest;
}
void NotifyLButtonUp(NcWidgetBase* hittest,CWindow* window,const CPoint& point){
ATLASSERT(hittest);
ATLASSERT(window);
hittest->OnLButtonUp(window,point);
m_lbtn_hittest_ = NULL;
}
LRESULT OnNcLButtonDblclk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
CPoint point_;
this->GetPosition(&point_,lParam);
// 依次处理每一个widget
CPoint widget_point_;
for(RIter iter_ = m_widgets_.rbegin();
iter_ != m_widgets_.rend();
++ iter_){
if((*iter_)->OnNcHitTestBase(point_,&widget_point_)){
(*iter_)->OnLButtonDblClk(pT,widget_point_);
return TRUE;
}
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
LRESULT OnNcLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
CPoint point_;
GetPosition(&point_,lParam);
// 先处理m_lbtn_hittest_
if(m_lbtn_hittest_){
// 这里的point_是不准确的
this->NotifyLButtonUp(m_lbtn_hittest_,pT,point_);
return TRUE;
}
// 依次处理每一个widget
CPoint widget_point_;
for(RIter iter_ = m_widgets_.rbegin();
iter_ != m_widgets_.rend();
++ iter_){
if((*iter_)->OnNcHitTestBase(point_,&widget_point_)){
this->NotifyLButtonUp(*iter_,pT,widget_point_);
return TRUE;
}
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
T* pT = static_cast<T*>(this);
// 先处理m_lbtn_hittest_
if(m_lbtn_hittest_){
pT->SendMessage(WM_NCLBUTTONUP,wParam,lParam);
return TRUE;
}
// 否则交给默认处理
bHandled = FALSE;
return TRUE;
}
////////////////////////////////////////////////////////////
// 子窗口相关
void AddWidget(NcWidgetBase* widget){
ATLASSERT(widget);
this->m_widgets_.push_back(widget);
// 调用Create函数
T* pT = static_cast<T*>(this);
widget->OnCreate(pT);
}
private:
void GetPosition(CPoint* point,LPARAM lParam){
CPoint point_(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
T* pT = static_cast<T*>(this);
// 屏幕坐标转换成窗口坐标
CRect rcWindow;
pT->GetWindowRect(rcWindow);
point_.Offset(-rcWindow.TopLeft());
*point = point_;
}
private:
Vector m_widgets_;
// 跟踪鼠标hover的控件
NcWidgetBase* m_move_hittest_;
// 跟踪被左键单击的控件
NcWidgetBase* m_lbtn_hittest_;
// 跟踪鼠标移出
bool m_mouse_tracking_;
};
class BitmapBtn : public NcWidgetBase{
public:
virtual void OnCreate(CWindow* window){
LoadBitmapFromFile(&m_bitmap_normal_,_T("res\\close_normal.bmp"));
LoadBitmapFromFile(&m_bitmap_hover_,_T("res\\close_hover.bmp"));
LoadBitmapFromFile(&m_bitmap_press_,_T("res\\close_press.bmp"));
LoadBitmapFromFile(&m_bitmap_disable_,_T("res\\close_disable.bmp"));
m_mask_color_ = RGB(255, 0, 255);
m_hover_ = false;
m_pressed_ = false;
m_disable_ = false;
}
virtual void OnPaint(CWindow* window,CWindowDC* dc)
{
CBitmap* bitmap_ = NULL;
if(m_disable_)
bitmap_ = &m_bitmap_disable_;
if(m_pressed_)
bitmap_ = &m_bitmap_press_;
else if(m_hover_)
bitmap_ = &m_bitmap_hover_;
else
bitmap_ = &m_bitmap_normal_;
CSize size_;
this->GetPrefSize(&size_);
CDC dcMemory;
dcMemory.CreateCompatibleDC(*dc);
dcMemory.SelectBitmap(*bitmap_);
dc->TransparentBlt(
0,
0,
size_.cx,
size_.cy,
dcMemory,
0,
0,
size_.cx,
size_.cy,
m_mask_color_);
}
virtual void OnMouseEnter(CWindow* window,const CPoint& point){
m_hover_ = true;
RePaint(window);
}
virtual void OnMouseLeave(CWindow* window){
m_hover_ = false;
RePaint(window);
}
virtual void OnLButtonDown(CWindow* window,const CPoint& point){
m_pressed_ = true;
RePaint(window);
window->SetCapture();
}
virtual void OnLButtonUp(CWindow* window,const CPoint& point){
m_pressed_ = false;
RePaint(window);
::ReleaseCapture();
}
virtual void OnLButtonDblClk(CWindow* window,const CPoint& point){
CPoint local_p_(point);
PointToGlobal(window,&local_p_);
window->SendMessage(WM_NCLBUTTONDOWN,HTNOWHERE,MAKELPARAM(local_p_.x,local_p_.y));
}
void GetPrefSize(CSize* size){
ATLASSERT(size);
m_bitmap_normal_.GetSize(*size);
}
private:
CBitmap m_bitmap_normal_;
CBitmap m_bitmap_hover_;
CBitmap m_bitmap_press_;
CBitmap m_bitmap_disable_;
COLORREF m_mask_color_;
bool m_hover_;
bool m_pressed_;
bool m_disable_;
};
class BitmapStatic : public NcWidgetBase{
public:
virtual void OnCreate(CWindow* window){
LoadBitmapFromFile(&m_bitmap_,_T("res\\static.bmp"));
m_mask_color_ = RGB(255, 0, 255);
}
virtual void OnPaint(CWindow* window,CWindowDC* dc)
{
CSize size_;
this->GetPrefSize(&size_);
CDC dcMemory;
dcMemory.CreateCompatibleDC(*dc);
dcMemory.SelectBitmap(m_bitmap_);
dc->TransparentBlt(
0,
0,
size_.cx,
size_.cy,
dcMemory,
0,
0,
size_.cx,
size_.cy,
m_mask_color_);
}
void GetPrefSize(CSize* size){
ATLASSERT(size);
m_bitmap_.GetSize(*size);
}
virtual bool OnHitTest(const CPoint& point){return false;}
private:
CBitmap m_bitmap_;
COLORREF m_mask_color_;
};
#include "title_fuck.h"
class CMainDlg :
public CDialogImpl<CMainDlg>,
public TitleWidget<CMainDlg,false>
{
typedef TitleWidget<CMainDlg,false> BaseClass;
public:
enum { IDD = IDD_MAINDLG };
BEGIN_MSG_MAP(CMainDlg)
CHAIN_MSG_MAP(BaseClass)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ... ...
this->AddWidget(&m_nc_button_);
this->AddWidget(&m_nc_static_);
return TRUE;
}
void OnNcLayout(CWindow* window,UINT nType, CSize size){
CSize size_;
m_nc_button_.GetPrefSize(&size_);
CRect rect_(0,1,size_.cx,size_.cy);
rect_.OffsetRect(size.cx - rect_.Width() - 100,0);
m_nc_button_.LayoutWindow(rect_);
m_nc_static_.GetPrefSize(&size_);
rect_.SetRect(0,1,size_.cx,size_.cy);
rect_.OffsetRect(size.cx - rect_.Width() - 140,0);
m_nc_static_.LayoutWindow(rect_);
}
private:
BitmapBtn m_nc_button_;
BitmapStatic m_nc_static_;
};
|
|