RibbonX:自定义Office 2007功能区——回调(一)
RibbonX:自定义Office 2007功能区
第五章 回调:对自定义UI添加功能的关键-学习笔记
—————————————————–
回调,即使定制能够工作的代码。如果没有回调,UI可能看起来是漂亮的,但只是一个漂亮的Ribbon。当然,除了从内置的控件不需要自定义回调外。
下面介绍XML与VBA组合。需要在XML代码中指定回调,然后编写VBA代码来匹配和处理回调。
一、回调是什么,为什么需要回调
回调是子过程和函数,被自定义UI使用,使得定制的UI能够工作。例如,当设置某按钮的onAction属性并装载时,一旦单击该按钮,就产生回调,即在属性中指定的操作。如果没有找到指定的操作,那么回调将失败,因为代码中发生了例外,即在属性中指定的回调在VBA中不存在。
使用自定义UI中的功能时,UI将调用VBA项目,搜寻指定的函数或过程。如果找到,则将其值传回UI;如果没有发现指定的函数或过程,那将产生错误的结果。
有两种主要的方式来创建回调:
(1)直接在VBE的标准模块中输入过程或函数;
(2)使用工具生成过程,例如Office 2007 CustomUI Editor。
使用工具,例如Office 2007 CustomUI Editor的主要优势之一是能返回一个回调签名,也称作subprocedure stub,对于XML代码中每个属性都有一个回调需要处理,接受回调作为值的属性包括onAction、getVisible和getImage。
使用CustomUI Editor还能避免错误,节省时间。
当项目装载且需要访问某些回调并运行,意味着如果回调处理(即响应回调的VBA代码)在该项目中不存在,则将产生错误消息。
二、为动态回调建立文件
为了使用自定义控件工作,文件必须启用宏,否则不能添加或运行VBA代码。
1、捕获IRibbonUI对象
IRibbonUI对象引用Ribbon用户界面。
在VBA中使用的关键之一是使整个Ribbon对象无效(因而能改变Ribbon的某项特征)或者使Ribbon中指定的控件无效(因而能改变该控件的某项特征)。
(1)调整XML来包括onLoad
为了使用IRibbonUI对象,需要在VBA中对其设置。此时,需要对UI的onLoad属性指定值,这能通过为onLoad属性指定回调来实现。
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui” onLoad=”rxIRibbonUI_onLoad”>
因为onLoad属性的值是一个回调,所以需要在VBA代码中对其进行处理。接着,使得在工程中能够使用IRibbonUI对象。
(2)创建VBA代码处理onLoad事件
可能注意到,以前称onLoad为属性,而现在将其称为事件。这是因为在XML文件中,能为许多属性定义值,例如onAction、getLabel和onLoad。一旦为某属性赋值,如果能以某种方式触发,将导致事件发生。
因为IRibbonUI对象用于应用程序,所以需要在标准模块的全局声明部分对其声明。
Dim grxIRibbonUI As IRibbonUI
‘Callback for customUI.onLoad
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
Set grxIRibbonUI = ribbon
End Sub
注意,此时在对代码作出变化后,需要保存、关闭并重新打开工程,才能使改变生效。
三、生成第一个回调
─—如何知道使用哪个回调签名
─—例如,toggleButton有下列签名:
Sub rxtgl_click(control as IRibbonControl,pressed as boolean)
一个普通按钮的签名:
Sub rxbtn_click(control as IRibbonControl)
1、从头开始编写回调
如果知道了回调签名,则不必使用标准的形式声明参数。例如,有一个使用下列XML的toggleButton:
<toggleButton
id=”rxtgl”
label=”Toggle”
size=”large”
onAction=”rxtgl_click”
imageMso=”FormatPainter”/>
编写rxtgl_click回调如下:
Sub rxtgl_click(rxctl As IRibbonControl,toggled As Boolean)
If toggled Then
MsgBox “I am toggled …And my ID is “ & rxctl.ID,vbInformation
End If
End Sub
注意,无论何时都必须是“正确类型的正确参数”。
也能更改onLoad回调签名来满足需要,如下:
Sub rxIRibbonUI_onLoad(MyRibbon As IRibbonUI)
Set grxIRibbonUI=MyRibbon
End Sub
但是,使用标准的签名及其参数,使他人更容易理解。
表:不同对象属性的回调签名
属性 回调签名
onLoad (ribbon as IRibbonUI)
getLabel,getPressed,
getEnabled,getImage,
getScreentip,getVisible,etc (control as IRibbonControl,ByRef returnedVal)
onAction(对toggleButton) (control as IRibbonControl,pressed as Boolean)
onAction(对按钮) (control as IRibbonControl)
2、使用Office CustomUI Editor生成回调
(1)在CustomUI Editor中打开包含XML代码的Excel或Word文件。(对Access文件,复制并粘贴XML代码到空的CustomUI Editor代码窗口)
(2)单击“Generate Callbacks”按钮。
(3)出现一个新的Callbacks选项卡。
(4)复制并产生的代码粘贴到VBA工程中。
下图为使用CustomUI Editor生成回调的示例:

3、理解文件打开时事件的顺序
表:当打开文件后选项卡获取焦点时事件顺序
事件 选项卡获取焦点 选项卡获取焦点 按下ALT键 鼠标在其上方
onLoad 最顶级的事件,当装载UI时发生
getVisible 1 1 N/A N/A
getLabel 2 3 N/A N/A
getImage 3 4 N/A N/A
getEnabled 4 2 N/A N/A
getKeytip N/A N/A 1 N/A
getScreentip N/A N/A N/A 1
getSupertip N/A N/A N/A 2
4、能够有具有相同名称但不同签名的两个回调吗?
VBA不允许在相同项目中的两个回调使用相同名称但不同的签名。
然而,如果回调在不同的工程中,则相同的回调名称能够有不同的签名。因此,如果同时有一个以上的Word和/或Excel文档打开,可能发现回调返回不可预料的结果。因为如果多个操作与一个回调名称相联系,那么将运行当前文档的回调。
假设打开一个安装了两个加载项的Excel工作簿,三个项目都有一个带有称为rxbtnnsQaShared的控件,当单击UI中该控件时,所期望的是添加一个新工作簿,然而将出现一个消息框。检查后,发现为所有三个按钮都使用了相同的回调。此时,可以使用断点调试,看看单击操作调用了哪个回调。
上述表明,只要在不同工程中,虽然允许使用带有不同签名的一致名称,但这不是一个好主意。
四、调用位于不同工作簿中的过程
与上面所讲的情况相似,如果XML代码运行位于不同工作簿中的VBA,也会碰到类似的问题。
假设有两个工作簿:Book.xlsm和Book2.xlsm,希望在第一个工作簿中添加一个按钮,运行第二个工作簿中的过程,那么使用下面的XML代码创建UI:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui“>
<ribbon>
<tabs>
<tab id=”rxtabDemo”
label=”My Custom Tab”
insertBeforeMso=”TabHome”>
<group id=”rxgrpDemo”
label=”My Demo Group”>
<button id=”rxbtnDemo”
label=”My Demo Button”
size=”large”
onAction=”Book2.xlsm!rxbtnDemo_click”
imageMso=”FileStartWorkflow”/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
在Book2.xlsm的标准模块中,放置下列代码:
Sub rxbtnDemo_click(control As IRibbonControl)
MsgBox “您调用了位于:” & ThisWorkbook.Name & “中的过程.”
End Sub
注意,必须要打开工作簿。
如果希望onAction属性指向加载项,那么简单地在onAction代码名称前使用[add-in name].xlam前缀,例如:
onAction=”myAddIn.xlam!rxbtnDemo_click”
然后,在加载项模块中放置回调VBA代码:
Book3.xlam!rxbtnDemo_click
此时,必须加上前缀xlam!。注意,如果在UI的onAction属性下指定的过程中xlsm和xlam有相同的名称,则该事件会运行包含在活动工作簿中的代码。

发表评论