实现思路思路:
在实现之前,需要先了解IE下 ToolBar的工作原理,关于这部分内容这里就不多介绍,http://www.vckbase.com/上有很多介绍,里面列举了一些如何创建基本的IE ToolBar的方法及原理。了解创建原理后,按照里面的套路,就可以亦步亦趋的生成基本框架。
IE的ToolBar的开发,实质上也就是一个一般的ToolBar开发,为了加速开发,我们选择基于MFC的开发。因此需要在项目的stdafx.h里加入MFC相关的头文件。并写一个类(CMyToolBar)继承自MFC的CToolBar类。今后所有的操作都基于这个类来进行。
ToolBar在实现的时候,根据实现的过程,分为2个部分:
1. 上的控件生成ToolBar
2. 的弹出子菜单生成及弹出子菜单的事件响应ToolBar
1. 上的控件生成ToolBar
目前在ToolBar里添加了4个类型的控件
l 图片Lable
l 文字Lable
l TextBox
l Button
a) 图片Label
因为CToolBar不支持同时显示不同宽度的图片Button,因此,要显示图片,我们只能用一些其它取巧的方法。设置一个不处理事件的Button,宽度和要显示的图片的宽度一样,然后创建一个带图片的Label,将Button覆盖。这样就只看到带图片的Label了。
创建带图片Label的四个步骤:
1) 通过
InsertButton 方法创建一个占位Button
2) 读取要显示图片(BMP)
3) 通过
SetButtonInfo方法重新设置Button宽度(与读取图片等宽)
4) 创建CStatic,并
SetBitmap设置要显示的图片
p.s. 实际在显示bitmap图片的时候,图片的背景色并不是透明的,因此显示效果不是很好,在实际应用中,采用了一个
CTransparentImage 的控件实现透明背景。
p.s. 如果需要显示的图片是ICON,则无须透明背景的设置,只要在编辑ICON的时候设置好透明色即可。不过考虑到CStatic在显示ICON的时候,是按照正方形方式去显示,因此非正方形的ICON在显示的时候会被缩放,目前还没找到合适的解决办法。
p.s. 插入一个占位Button的方法:
CToolBarCtrl
&
tbc
=
GetToolBarCtrl
();
TBBUTTON
tButton
;
ZeroMemory
(&
tButton
,
sizeof
(
TBBUTTON
));
tButton
.
fsStyle
=
TBSTYLE_BUTTON
;
tButton
.
idCommand
=
IDC_PICTURE
;
tButton
.
iBitmap
= -1;
tbc
.
InsertButton
(-1, &
tButton
);
p.s. 修改一个Button的宽度的方法
CToolBarCtrl
&
tbc
=
GetToolBarCtrl
();
TBBUTTONINFO
tif
;
tif
.
cbSize
=
sizeof
(
tif
);
tif
.
dwMask
=
TBIF_SIZE
;
tif
.
fsStyle
=
TBSTYLE_AUTOSIZE
;
tif
.
cx
=
bmpInfo
.
bmWidth
+ 4;
//
设置
Button
的宽度
tbc
.
SetButtonInfo
(
IDC_PICTURE
, &
tif
);
b)
文字Label
文字Label的创建方法和图片Label步骤一样,只不过缺少设置图片过程,不过占位用的Button宽度还是需要通过获得Label显示的文字宽度来进行调整。
c)
TextBox
TextBox的创建和Label的方法和过程一样,基本上也是创建后即可使用。
不过需要注意的是,直接创建的TextBox在运行的时候,无法处理某些特殊功能的按键,例如:“退格键”。原因应该是IE没有把所有的键盘消息传递给它的子控件,因此TextBox自然无法使用“退格键”进行文本的删除操作。
解决方案有两个:
1. 实现
IInputObject接口,来获得用户输入信息
2. 通过钩子函数拦截系统的键盘消息
考虑到实现
IInputObject接口的方法示例代码太少,无从研究,因此采用第二种方案,采用钩子函数拦截键盘消息。
1. 新建一个CMyEdit类,继承自CEdit。
2. 重载
OnSetFocus和
OnKillFocus方法。
当TextBox获得焦点(
OnSetFocus)的时候通过
SetWindowsHookEx创建一个消息钩子
当TextBox失去焦点(
OnKillFocus)的时候通过
UnhookWindowsHookEx释放钩子
3. 实现一个删除字符功能的函数
因为IE已经屏蔽了退格键,因此在拦截到用户输入的键盘消息后,不能将消息转发TextBox控件,消息会再次被IE拦截并屏蔽。这里只能通过自己实现删除文字的功能。
void
CMyEdit
::
KillChar
()
{
int
nStartChar
,
nEndChar
;
GetSel
(
nStartChar
,
nEndChar
);
if
(
nStartChar
==
nEndChar
)
{
if
(
nStartChar
> 0)
nStartChar
--;
}
this
->
SetSel
(
nStartChar
,
nEndChar
);
this
->
ReplaceSel
(
_T
(
""
));
}
4. 实现处理钩子功能的函数
LRESULT
FAR
PASCAL
GetMsgProc
(
int
nCode
,
WPARAM
wParam
,
LPARAM
lParam
)
{
LPMSG
lpMsg
= (
LPMSG
)
lParam
;
try
{
if
(
nCode
>= 0 &&
PM_REMOVE
==
wParam
)
{
if
(
lpMsg
->
message
==
WM_KEYUP
)
{
if
(
lpMsg
->
wParam
==
VK_BACK
)
{
if
(
pEditMenuBar
!=
NULL
)
{
if
(
pEditMenuBar
->
m_edit
.
IsDialogMessage
(
lpMsg
) ==
TRUE
)
{
pEditMenuBar
->
m_edit
.
KillChar
();
}
}
}
}
}
}
catch
(
CString
&
error
)
{
CLog
::
WriteLogData
(
error
.
GetBuffer
(0));
}
catch
(...) {
//
捕捉异常,免得发生错误后系统崩溃
}
return
CallNextHookEx
(
g_hKeyHook
,
nCode
,
wParam
,
lParam
);
}
d) Button
ToolBar本身在设计的时候,就是为了放置Button的,因此添加一个Button的操作比较简单。按照上边的方法设计即可,不需要再创佳对应的Button控件。不过郁闷的是,一旦Button指定了图片,
SetButtonInfo方法就不能修改Button的大小了。
在实际设计过程中,最后一个Button需要在Button右边加一个小三角,用于提示这里可以弹出一个用于选择的菜单,方法行简单,通过设置Button的属性即可
tbc
.
SendMessage
(
TB_SETEXTENDEDSTYLE
, 0, (
LPARAM
)
TBSTYLE_EX_DRAWDDARROWS
);
DWORD
dwStyle
=
this
->
GetButtonStyle
(
this
->
CommandToIndex
(
MenuBtn
.
idCommand
));
dwStyle
|=
TBSTYLE_DROPDOWN
;
this
->
SetButtonStyle
(
this
->
CommandToIndex
(
MenuBtn
.
idCommand
),
dwStyle
);
2.创建弹出子菜单,及子菜单的事件处理。
ToolBar的所有功能都集中在弹出菜单里。这部分功能其实行简单,就是一个在初始的时候动态创建菜单,并且在菜单事件被触发后,执行相应的逻辑代码而已。
菜单通过MFC的CMenu类进行创建,当ToolBar的Button被按下的时候(触发
OnLButtonDown事件)的时候,通过CMenu里的
TrackPopupMenu显示子菜单,并在菜单
我们通过重载CMyMenu的OnCommand方法,实现响应菜单消息,当弹出子菜单的时候,我们通过
LOWORD
(
wParam
) 获响应菜单的ID,并根据菜单ID来处理响应的逻辑代码。