二、处理加载宏函数 加载宏函数似乎是制作加载宏中最简单的,通常它只需要在模块中写一段Function代码,它就会和EXCEL自身的函数一样使用,并且出现在“插入函数”对话框的列表中。关于函数的制作,再没有其它的吗? 1.为函数添加说明信息 至少你可以通过对象浏览器设置“属性”为函数添加一段说明信息(对需要换行的说明可以在编辑时使用组合键CTRL+ENTER),这些信息当用户使用“插入函数”对话框时就会看到。需要说明的是,在对象浏览器中为函数添加说明信息必须在“另存为”加载宏之前,一旦文件名的后缀变为了XLA,函数的属性设置将不被接受。 关于为函数定制说明信息,请参见:图示自定义函数描述信息及有关介绍。 现在,请你新建一个工作簿,插入模块,粘贴下面的代码: Function dx(n) ' by gly1126 金额小写转换为大写 dx = Replace(Application.Text(Round(n+0.00000001, 2), "[DBnum2]"), ".", "元") dx = IIf(Left(Right(dx, 3), 1) = "元", Left(dx, Len(dx) - 1) & "角" & Right(dx, 1) & "分", IIf(Left(Right(dx, 2), 1) = "元", dx & "角整", IIf(dx = "零", "", dx & "元整"))) dx = Replace(Replace(Replace(Replace(dx, "零元零角", ""), "零元", ""), "零角", "零"), "-", "负") End Function 如果觉得必要,你可以设置文件属性(见一、1.(2))并为该函数添加说明,先把它做为普通的工作簿保存(我们后面还会继续用它)再另存为XLA,然后感受一下它的效果吧。 对已经成为XLA文件的函数说明的添加及修改并不需要总是手工先还原为XLS文件,我们稍后就会提到MacroOptions方法。在此之前,先来说一下与加载宏相关的Workbook事件: (1)AddinInstall和AddinUninstall。这两个事件分别发生在加载宏加载和卸载时的,因此使用这两个事件的工作簿一定是XLA工作簿,你需要记住的是,它们在加载宏作用期内各自只会发生一次,加载宏加载后每次EXCEL的打开和关闭都不会触发它们。 (2)Open和BeforeClose。和上两个事件不同,这两个事件在加载宏作用期内会被多次触发,除了分别发生在AddinInstall后和AddinUninstall前之外,每次打开和关闭EXCEL时都会触发它们。 清楚了上述特性,你就应该知道如何合理安排加载宏的初始化代码。 2.为函数分类 默认情况下,当用户使用“插入函数”时,加载宏函数会被分类放在“用户定义”类别中。 哦,没有个性!有的朋友甚至还会有被歧视的感觉呢,怎样才能和EXCEL自身的函数一样被放在“财务”类呢?我们会想到MacroOptions方法: Application.MacroOptions Macro:="dx", Category:=1 不熟悉这个方法不要紧,看完后面的例子你再去查看一下它的帮助,很快就会掌握的。 现在的问题,上面的语句放在哪儿呢?首先把它放在AddinInstall事件中看看,你会发现,在第一次加载时,目的确实达到了,但当你关闭EXCEL重新打开时,却发现它又回到了“用户定义”中,看来需要放在Open事件中: Private Sub Workbook_Open() ThisWorkbook.IsAddin = False Application.MacroOptions Macro:="dx", Category:=1 ThisWorkbook.IsAddin = True ThisWorkbook.Saved = True End Sub 你会发现,除了我们需要的,又增加了3条语句,这是因为加载宏文件与普通EXCEL文件除了后缀形式上的区别外,一个重要的内在区别就是IsAddin属性,该属性为True 说明是加载宏工作簿,MacroOptions方法对宏的设置不能在隐藏的工作簿中进行,需要先将还原为普通工作簿,加入宏设置后再改回。这两次改变不会触发AddinInstall和AddinUninstall事件,但EXCEL会记住普通EXCEL文件的修改,因此在完成设置后,还需要加一句ThisWorkbook.Saved = True以使EXCEL忘记这种改变。 下面列出了EXCEL内部分类对应的Category参数的整数。 1:财务 2:日期与时间 3:数学与三角函数 4:统计 5:查找与引用 6:数据库 7:文本 8:逻辑 9:信息 如果你不想记住这些整数的含义,你可以直接写成: Application.MacroOptions Macro:="dx", Category:= "财务" 那么是否可以为加载宏函数增加一个新类别呢?很简单!只需要将上面的Category参数改变一下就可以了: Application.MacroOptions Macro:="dx", Category:= "财务扩展函数" 上句会在“插入函数”对话框中增加一个新类别“财务扩展函数”,并把dx函数放入其中。 MacroOptions方法还有其它一些参数,可以帮助我们,包括为函数添加说明,下面语句在分类的同时会为函数增加说明。 Application.MacroOptions Macro:="dx", Description:="金额小写转换为大写" & vbCr & "参数N:要转换的金额。", Category:="财务扩展函数" 让我们再次回到Open事件中,看看这3句代码: ThisWorkbook.IsAddin = False ThisWorkbook.IsAddin = True ThisWorkbook.Saved = True 在加载宏文件中使用类似在无耐情况下才采用的变通代码,达到的目的仅仅是一般人并不注意的函数分类,我想我已经把你引入歧途,真的很抱歉。我该如何纠正呢? 我无意保留一个没有多大实用价值的技巧,我更希望由你说出来…… (我会等你一个礼拜) 呵呵,也不能全怪我,因为几乎所有的公开的资料都是这样介绍的,事实上,实现函数的说明和分类根本用不着明示的代码,这意味着在open事件中使用MacroOptions根本就是多余的。因为EXCEL会记录并保存MacroOptions的操作,你只需在设计阶段,在立即窗口,执行需要的MacroOptions操作,或者写一段MacroOptions操作代码,然后再删除它就可以了。要记住的是,执行后一定别忘了在VBE中点击保存。结果竟然如此简单!请参考我在后面给你提供的附件实例。 3.函数规范 有些朋友认为:Function和Sub的区别仅仅在于是否有返回值,在Sub中使用的代码同样可以在Function中使用。这种认识最多对了一半。是的,对于在代码中调用的Function和Sub,除了“返回值”,它们几乎没有区别,但是,全局宏的函数是准备给用户在工作表中使用,象我们前面的做的函数,用户在使用时,通常会在工作表的B2单元格中输入“=dx(A1)”,如果一个函数是为工作表准备的,代码就要受到限制。先来看一个错误的函数: Function TTT(rg As Range) As String rg.Value = rg.Value + 1 TTT = rg.Value End Function 上面的函数试图将参数区域的值先加1,然后返回其值。如果你在代码中使用 N=TTT([a1]) 不会有任何问题,现在,你在A2单元格输入公式“=ttt(A1)”看看。 限于篇幅,本文不再探讨理论问题,而是直接给出这些应该注意的结论: (1)严格遵循“黑匣子”理论,不要试图去改变外部对象的属性,包括参数对象,即使它们是传址方式的。对外部对象值的改变,会导致函数的结果错误,如你在上面看到的“#VALUE!”,其它属性的改变,通常会被忽略。 (2)不要使用Volatile 方法,除非你要构建的函数确实是象RAND类型的易失性函数。在函数中加入: Application.Volatile 会告诉系统该函数是易失性函数,则当工作表的任何区域发生改变时,该函数都会被重算。这将严重影响系统的效率。要做到这一点,应当将所有影响函数值变动的区域都作为参数,即使某些区域是固定的也要作为参数传递。 (3)函数中可以使用可选参数,但可选参数应避免为Range类型。因为使用Range类型的可选参数,将不可避免地使用Application.Volatile。
[此贴子已经被作者于2007-8-10 14:25:18编辑过] |