分享
 
 
 

如何用VC++ 5.0实现工具栏及其属性的控制

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

如何用VC++ 5.0实现工具栏及其属性的控制

任志民

VC++ 5.0风格的工具栏具有平面外观,左边带有一个“把手”,你可以通过鼠标拖动这个“把手”来移动工具栏。工具栏各组间带有分隔线(如图1所示)。当鼠标在工具栏上面移动时,工具栏上的相应按钮会突出显示。本文所讨论的增强型工具栏CEnhanceToolBar类由CToolBar类所派生,是CToolBar类的补充和扩展。

如果你并不在乎工具栏有没有“把手”的话,要生成平面工具栏是十分简单的。你只需要在CMainFrame的OnCreate()函数中添加一句话就可以(必须加在工具栏生成函数之后,因为MFC在生成工具栏时,要清除其式样):

//MainFrm.cpp

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

......

if(!m_wndToolBar.Create(this)

//!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1; // fail to create

}

m_wndToolBar.ModifyStyle(0,TBSTYLE_FLAT);

//设置工具栏为平面格式

......

}

如果你的计算机安装了4.71.1712.3版本的COMCTL32.DLL(该动态库随IE 4.0一同发行),那就更好了,你的工具栏就会自动绘制分隔线。你可以通过鼠标拖动工具栏的非按钮区域来移动这种工具栏。GetRight中的工具栏就是这样的。

如果你要得到更好看(更“专业”)的工具栏,那么就请跟我一步步地做下去。

1.添加一个新类,本文中叫做CEnhanceToolBar类,由CToolBar类派生。

2.为CEnhanceToolBar类添加成员变量和函数的声明,并且根据你的需要设置其访问属性。

//EnhanceToolBar.h

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CEnhanceToolBar)

//按钮状态变化时调用此函数

virtual void OnUpdateCmdUI(CFrameWnd*pTarget,BOOL bDisableIfNoHndler);

//}}AFX_VIRTUAL

// Implementation

public:

void DrawGrip(CWindowDC*pDC,CRect& rectWindow);//“把手”绘制函数

void EraseNonClient();//擦除非客户区

void DrawSpace();//分隔线绘制函数

void RedrawBackground();//背景重绘函数

private:

int ButtonNumber;//工具栏的按钮数(包括分隔线)

COLORREF HiLight, Shadow;//3D控件的加亮色和阴影色

3.添加成员函数的定义:

//EnhanceToolBar.cpp

void CenhanceToolBar :: OnUpdateCmdUI(CframeWnd * pTarget, BOOL bDisableIfNoHndler)

{//按钮状态变化时调用此函数

static CUIntArray Styles;

int Index;

UINT dwStyle;

for (Index = 0; Index < ButtonNumber; Index++)

{

dwStyle = GetButtonStyle(Index);

Styles.SetAtGrow(Index,dwStyle);//保存按钮的式样

}

CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);

//调用基类的处理函数

for (Index = 0; Index < ButtonNumber; Index++)

{//设置选中的按钮(checked button)为按下的状态

dwStyle = GetButtonStyle(Index);

if (dwStyle & TBBS_DISABLED)

return;//如果按钮为禁用状态,则返回(避免闪烁)

if (dwStyle & TBBS_CHECKBOX)

{

if (dwStyle & TBBS_CHECKED)

dwStyle |= TBBS_PRESSED;

else

dwStyle &= ~TBBS_PRESSED;

SetButtonStyle(Index,dwStyle);//设置按钮的式样

}

}

//检查按钮的式样是否改变(按下或释放)

for (Index = 0; Index < ButtonNumber; Index++)

{

dwStyle = GetButtonStyle(Index);

if (Styles[Index] != dwStyle)

{

RedrawBackground();//重新绘制背景

Invalidate();//重新绘制整个工具栏

break;//已更新整个工具栏,因此没必要继续循环

}

}

}

void CEnhanceToolBar::DrawGrip(CWindowDC *pDC, CRect& rectWindow)

{//绘制把手

if (IsFloating())//如果工具栏是浮动状态,则不绘制“把手”

return;

CRect GripRect = rectWindow;//得到把手的矩形区域

GripRect.DeflateRect(1,1);//矩形区域的各边向中心靠近一个像素

if (m_dwStyle & CBRS_ORIENT_HORZ)

//如果工具栏为水平状态,则“把手”在左边

{

GripRect.right = GripRect.left + 3;//绘制第一条隆起的棱

pDC->Draw3dRect(GripRect, HiLight, Shadow);

GripRect.OffsetRect(4,0);//绘制第二条隆起的棱

pDC->Draw3dRect(GripRect, HiLight, Shadow);

}

else//如果工具栏为垂直状态,则“把手”在顶部

{

GripRect.bottom = GripRect.top + 3;//绘制第一条隆起的棱

pDC->Draw3dRect(GripRect, HiLight, Shadow);

GripRect.OffsetRect(0,4);//绘制第二条隆起的棱

pDC->Draw3dRect(GripRect, HiLight, Shadow);

}

}

void CEnhanceToolBar::DrawSpace()

{//绘制分隔线

CClientDC dc(this);

for (int Index = 0; Index < ButtonNumber; Index++)

{

UINT dwStyle = GetButtonStyle(Index);//获得按钮的类型

if (dwStyle & TBBS_SEPARATOR)//如果是分隔线

{

CRect rect;

GetItemRect(Index,rect);//获得矩形区域

if (m_dwStyle & CBRS_ORIENT_HORZ)

//工具栏为水平时分隔线为垂直

{

int w = rect.Width();

rect.DeflateRect((w-2)/2,0);//将矩形缩减为2~3个像素宽

dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线

}

else//分隔线为水平

{

rect.left = rect.left - m_sizeButton.cx;

rect.right = rect.left + m_sizeButton.cx;

rect.top = rect.bottom+1;

rect.bottom = rect.top+3;

int h = rect.Height();

rect.DeflateRect(0,(h-2)/2);//将矩形缩减为2~3个像素高

dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线

}

}

}

}

void CEnhanceToolBar::EraseNonClient()

{//擦除非用户区

CWindowDC dc(this);

CRect rectClient;

GetClientRect(rectClient);

CRect rectWindow;

GetWindowRect(rectWindow);

ScreenToClient(rectWindow);

rectClient.OffsetRect(-rectWindow.left, -rectWindow.top);

dc.ExcludeClipRect(rectClient);

// 绘制非用户区的边界

rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top);

DrawBorders(&dc, rectWindow);

// 擦除非绘制部分

dc.IntersectClipRect(rectWindow);

SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC);

DrawGrip(&dc, rectWindow); //绘制“把手”

}

由于平面工具栏是透明的,所以当改变尺寸和移动时(例如当拖动工具栏时),就需要重绘背景。同样,当按钮状态改变时(按下或释放)也需要进行这种操作。

void CEnhanceToolBar::RedrawBackground()

{//重新绘制背景

CWnd* pParent = GetParent();//获得父窗口指针

if (pParent)

{

CRect drawrect,rect;

GetWindowRect(&rect);//获得工具栏矩形区域

drawrect = rect;

pParent->ScreenToClient(&drawrect);//转换为父窗口坐标

pParent->InvalidateRect(&drawrect);//重绘矩形区域

//绘制父窗口的其他工具栏

for (CWnd* pSibling = pParent->GetWindow(GW_CHILD);pSibling;

pSibling = pSibling->GetNextWindow(GW_HWNDNEXT))

{

if (pSibling == this)

continue;

drawrect = rect;

pSibling->ScreenToClient(&drawrect);//兄弟窗口的坐标

pSibling->InvalidateRect(&drawrect);//重绘矩形区域

}

}

}

4.利用ClassWizard给CEnhanceToolBar类添加消息映射:

//EnhanceToolBar.h

//{{AFX_MSG(CEnhanceToolBar)

afx_msg void OnPaint();

afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp);

afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos);

//}}AFX_MSG

//EnhanceToolBar.cpp

BEGIN_MESSAGE_MAP(CEnhanceToolBar, CToolBar)

//{{AFX_MSG_MAP(CEnhanceToolBar)

ON_WM_PAINT()

ON_WM_NCCALCSIZE()

ON_WM_WINDOWPOSCHANGING()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

5.为消息映射函数添代码:

void CEnhanceToolBar::OnPaint()

{

CToolBar::OnPaint();//绘制标准工具栏

EraseNonClient();//擦除背景

DrawSpace();//绘制立体分隔线

}

void CEnhanceToolBar::OnNcCalcSize(BOOL bCalcValidRects,

NCCALCSIZE_PARAMS FAR* lpncsp)

{// 计算非用户区域,用于调整“把手”

CToolBar::OnNcCalcSize(bCalcValidRects,lpncsp);

if (IsFloating())//如果工具栏是浮动状态,则不绘制“把手”

return;

if (m_dwStyle & CBRS_ORIENT_HORZ)

//如果工具栏为水平状态,则“把手”在左边

{

lpncsp->rgrc[0].left += 2;

lpncsp->rgrc[0].right += 2;

}

else//如果工具栏为垂直状态,则“把手”在顶部

{

lpncsp->rgrc[0].top += 4;

lpncsp->rgrc[0].bottom += 4;

}

}

void CEnhanceToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)

{//当尺寸、位置或Z方向次序变化时,程序框架调用此成员函数

CToolBar::OnWindowPosChanging(lpwndpos);

RedrawBackground();//重新绘制背景

}

6.编写构造函数,加入下面的代码:

CEnhanceToolBar::CEnhanceToolBar()

{

HiLight = ::GetSysColor(COLOR_3DHILIGHT);//获得3D控件的加亮色

Shadow = ::GetSysColor(COLOR_3DSHADOW);//获得3D控件的阴影色

ButtonNumber = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);

//获得工具栏的按钮数(包括分隔线)

}

把以上程序编译运行后,很酷的工具栏就会出现了。下面是几点说明:

(1)关于工具栏的其他格式请参考COMMCRTL.H。

#define TBSTYLE_TOOLTIPS 0x0100

#define TBSTYLE_WRAPABLE 0x0200

#define TBSTYLE_ALTDRAG 0x0400

#define TBSTYLE_FLAT 0x0800......

(2)如果你的计算机安装了4.71.1712.3版本的COMCTL32.DLL(随IE 4.0一同发行),那么你不需要添加下列的函数,这样就会更简单。

void DrawSpace();//分隔线绘制函数

void RedrawBackground();//背景重绘函数

virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler);

void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos);

(3)如何在工具栏的按钮中间加入一个分隔线呢?很简单,使用资源编辑器打开应用程序的工具栏,拖动一个按钮,使其与上一个按钮离开一定距离,松开鼠标键就可以了。

(4)已知的BUG有:

*当拖动工具栏使之成为垂直停泊工具栏、再拖动它使之成为浮动工具栏、再拖动它使之成为水平停泊工具栏时,“把手”的一部分会被遮住。

*如果你的计算机安装了4.71.1712.3版本的COMCTL32.DLL,那么当工具栏为垂直的或长度超过一行需要换行时,会出现工具栏的底边被剪切的情况。

以上介绍了如何在应用程序中生成VC++ 5.0式样的工具栏。文中的信息适用于Microsoft Visual C++(32-bit Edition)5.0版及后继版本所包含的Microsoft Foundation Classes (MFC)。要实现这种工具栏,你必须有4.7(或以上) 版本的COMCTL32.DLL,该动态库随IE 3.0一同发行,并且将作为Windows 98的标准组件之一。VC++ 5.0中已经附带了该动态库。

(北京市海淀区海淀路80号中科大厦 100080 任志民)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有