编写Function过程开发函数

本文深入探讨VBA中自定义函数(Function过程)的创建与应用,涵盖语法解析、参数处理技巧及实用案例,旨在帮助读者掌握高效开发自定义函数的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述:function过程即自定义函数,在插件中应用极广。应用范围小,过程仅仅能返回一个只或者多个数的组合,而sub过程既可以返回值,还可以对引用的对象进行修改,例如,引入单元格A1的值,对A1设置心的格式。Function可以获取到工作名称,但无法修改工作表的名称,funcion过程可以不实用参数,类似于工作表函数Rand和Now等。但绝大部分是需要一个参数或者多个。最大达到255个参数。

一、Function语法解析

[public | private | friend ] [static] function name [(arglist)][as type]

         [statements]

         [Name=expression]

[Exit function]

[statements]

         [name=expression]

End function

Public 可选,表示所有模块的所有其他过程都可以访问这个function过程,如果是在包含option private的模块中使用,则这个过程在该工程外是不可使用的

Private 可选的,表示只有包含其声明的模块的其他过程可以访问该function

Friend  可选的,智能在类模块中使用,表示该function过程在整个过程中都是可见的,但对于对象实例的控制者是不可见的

Static        可选,表示在调用之间将保留function过程的局部变量值,static属性对在该function外声明的变量不会影响,即使过程中也使用了这些变量

Name      必须的。Function的名称

Arglist      参数

Expression        可选的,function的返回值,函数名=值,将返回这个值

        

         调用方式:在工作表中通过公式调用,想内部函数一样在工作表中使用,也可以嵌套

         被其他过程调用。VBA.函数名(参数)

         跟sub过程一样都可以实现递归

二、过程的参数

a)        Sub过程的参数及应用

                        i.             参数语法:

[Optional] [ByVal | ByRef] [ParamArray] varname[()] [astype][=defaultvalue]

Opntional 可选,表示参数不是必须的关键字,如果使用了该选择,则后续参数都必须是可选的,而且必须都使用optional关键字声明,如果使用了paramarray 则任何参数都不能使用optional

ByVal 可选的  表示该参数按值传递

ByRef        可选表示该参数按地址传递,ByRef是默认的

ParamArray     可选,只用于arglist的最后一个参数,致命最后一个参数一个variant元素optional数组,使用paramArray关键字可以提供任何数据的参数。ParamArray关键字不能写ByVal ByRef或optional一起使用

Defaultvalue 可选的,任何常数或常数表达式,只对optional参数合法,如何类型为Object,则显示的默认值只能是nothing

验证操作权限案例

Sub 姓名(name AsString)

Dim i AsByte, rng As Range

For i = 1To Sheets.Count

    If ThisWorkbook.Sheets(i).name = "许可人员列表"Then: GoTo OK

    Next i

    MsgBox "不存在许可人员列表", 64

    Exit Sub

OK:

    If Len(name) < 2 Or Len(name) > 10Then MsgBox "长度智能是2到4,请重新录入", 64: Exit Sub

    Set rng = ThisWorkbook.Sheets("许可人员列表").Range("a1:a10").Find(name)

    If rng Is Nothing Then MsgBox "你无权操作"Else MsgBox "你具有操作权限"

End Sub

Sub 确认权限一() '手工指定姓名

Call 姓名(Application.InputBox("请输入姓名","确认权限", "", , , , , 2))

End Sub

Sub 确认权限二() '以当前表A1的值进行判断

    Call 姓名(ActiveSheet.Range("A1"))

End Sub

Sub 确认权限三()

    MsgBox Application.UserName

    Call 姓名(Application.UserName)

End Sub

                      ii.             按值传递和按地址传递。

Byval 变量 as long

Byval 表示参数按值传递。不能改变主程序传过来的实参

ByRef 表示参数按地址传递   可以改变主程序传过来的实参  默认

b)        Function过程的参数

Function只能传过来来实参的引用,不能更改传的实参的属性和值,可以返回对应的值

c)        开发自定义函数

                        i.             开发不带参数的function过程

1.        获取本机IP地址

Function IP() '获取IP地址

    Dim item

    '通过WMI技术获取网卡当前设置的IP地址

    For Each item InGetObject("winmgmts:\\" & "." &"root\cimv2").ExecQuery("select * fromWin32_NetworkAdapterConfiguration")

    If TypeName(item.IPAddress) <>"null" Then IP = item.IPAddress(0)

    Next

End Function

2.        返回有公式的单元格地址

FunctionFunAdd()

Dim rngAs Range, cell As Range

For Eachrng In ActiveSheet.UsedRange    '遍历当前表的已用区域

Ifrng.HasFormula Then '如果有单元格公式

Ifrng.Address <> Application.ThisCell.Address Then '如果变量rng的地址不等于当前公式所在的单元格的地址

If cellIs Nothing Then '如果变量cell为初始化

    Set cell = rng

    Else

    Set cell = Appcation.Union(cell, rng) '将变量cell与rng所代表的两个单元格对象合并为一个对象,赋值给cell

    End If

End If

End If

Next rng

 

If cellIs Nothing Then FunAdd = "" Else FunAdd = cell.Address(0, 0)  '返回结果

 

End Function

                      ii.             开发带有一个参数的function过程

1.        将人民币金额转换成大写

Function 大写(cell As String)

    Dim rmbs As String

    If cell = "" Or NotIsNumeric(cell) Then 大写 = "": Exit Function '如果参数为空,或者不是数值就返回空退出过程

    If cell = 0 Then 大写 = "零元整":Exit Function '如果参数为0则返回字符串并退出

    '将数值转换成中文大些,并将点替换成元,将负号替换成负

    rmbs = Replace(Replace(Application.Text(Round(cell,2), "[DBnum2]"), ".", "元"),"-", "负")

    '加入角与分,同事将最后的"零"替换成元整

    rmbs = IIf(Left(Right(rmbs, 3), 1) = "元",Left(rmbs, Len(rmbs) - 1) & "角" &Right(rmbs, 1) & "分", IIf(Left(Right(rmbs, 2), 1) = "元", rmbs& "角", IIf(rmbs = "零","", rmbs & "元整")))

    '将零元和零角替换成空

    rmbs = Replace(Replace(rmbs, "零元",""), "零角", "")

    大写 = rmbs '返回

   

End Function

2.        建立工作表目录

Function 工作表(Optional 序号) As String '声明函数,有一个参数为可选参数

Application.Volatile'声明为易失性函数

'如果未输入参数,则赋予变量序号为当前表的地址

If IsMissing(序号) Then 序号 =ActiveSheet.Index

If 序号 >Sheets.Count Then '如果参数大于工作表数量

工作表 = ""

Else

工作表 = Sheets(序号).name

End If

End Function

公式:

=HYPERLINK("#" & 工作表(ROW(A2))& "!A1",工作表(ROW(A1)))

3.        关机函数

Function 关机(Optional Close_Time As Byte = 10)

关机 = Close_Time

Shell"shutdown -s -t" & Close_Time '在指定的时间内关闭计算器,调用dos命令

End Function

                            方法收获:

                                     IsNumeric  哟关于判断参数是否是数字

                                     Replace     是用于替换的函数,但它与工作表函数replace有极大不同,与substitute函数极其相近

                                     IsMissing 用于判断函数的可选参数是否已经传递给过程。

                                     Index              属性则是值工作表在所有工作表中的序号---

                                     Shell   操作Dos命令,传递dos命令即可

 

                     iii.             开发带有两个参数的function过程

1.        对系统导出的数据分列,有两个参数,第二个参数为可选参数

'第一个参数为单元格引用,第二参数表示取分列后的第几列

Function Breakdown(rng As Range, Optional style As Byte = 1) AsString

Application.Volatile

On ErrorResume Next '防错

Dim i AsInteger, str As String

'将单元格的值以逗号为分隔符转换成一位数组,再从数组中取字符串赋值给变量str 取值的位置取决于第二个参数

str = Split(rng.Text, ",")(WorksheetFunction.RoundUp(style/ 3, 0) - 1)

If styleMod 3 = 1 Then '如果第二个参数除以3余数是1

For i = 1To Len(str) '遍历str的每一个字符

    If IsNumeric(Mid(str, i, 1)) Then ExitFunction '如果遇到数字,结束过程

    Breakdown = Breakdown & Mid(str, i, 1)'将取出的所有字符串连接起来左右返回值

    Next i

ElseIfstyle Mod 3 = 2 Then '如果参数除以3余数是2

    For i = 1 To Len(str)

    '如果遇到数字或者小数点,就取出并串联起来作为返回值

    If VBA.IsNumeric(Mid(str, i, 1)) Or Mid(str,i, 1) = "." Then Breakdown = Breakdown & Mid(str, i, 1)

    Next i

ElseIfstyle Mod 3 = 0 Then

    For i = 1 To Len(str) Step -1 '遍历str的每一个字符, 从右向左

    If IsNumeric(Mid(str, i, 1)) Then ExitFunction '如果遇到数字就结束过程

    Breakdown = Mid(str, i, 1) & Breakdown

    Next i

End If

If Err<> 0 Then Breakdown = "" '如果有错误就返空

End Function

调用:=Breakdown($A3,COLUMN(A1))

2.        中国式排名

Function 排名(区域, 成绩) '声明函数,有两个参数

Application.Volatile

Dim dicAs Object, rng, i As Integer '声明变量,包括字典对象

Set dic =CreateObject("scripting.dictionary") '声明字典对象变量

For Eachrng In 区域 '遍历区域

'如果变量rng等于成绩则为变量i 赋值1,如果变量rng大于成绩,则将rng的值追加到字典中

If rng = 成绩 Then i = 1Else If rng > 成绩 Then dic(rng * 1) = 1

Next

'如果变量i大于0,则区域中有数据等于成绩,那么排名结果等于字典中的数量+1 (字典对象是忽略重复值)

If i >0 Then 排名 = dic.Count + 1 Else 排名 = "超出范围" '如果成绩与区域中任何数据都不想等则返回超出范围

End Function

CreateObject(“scripting.dictionary”)用于创建一个字典对象,它的特点是成员不重复,而中国式排名,是需要忽略重复值的,即四人中第一人100分算第一名,两个99分并列第二名。

函数的两个参数都支持手动录入参数,而非仅仅限于单元格引用

Split   是一个数组函数,它可以将一个字符串按某个字符为分隔符转换成一个数组。

                     iv.             开发两个带有可选参数的function过程

声明方式:function col(optional rng as range,optional style as string=”A”)  声明函数名称,有两个可选参数   后面=“A” 方便于判断用户是否输入值

收获:

函数中费对象变量被忽略时,可以用isMissing来判断,如果是单元格对象,只能用nothing来判断。If rng is nothing

Address属性的两个参数使用0时可以将地址转换成相对引用,这有利于获取列标

日期类型的变量。不能用nothing来判断。判断是否等于0

                      v.             开发带有不确定参数的function过程

声明方式  functionConnect(ParamArray  rng() as Variant)  有多个参数,包括1-255个,在处理的时候使用for循环遍历。这个数组的大小使用UBound函数获取

收获:

UBound  返回一个 Long 型数据,其值为指定的数组维可用的最大下标

For i=0 To UBound(rng) 因为是变体量,for循环时默认下标应该为0

声明不确定参数规则:

1.      所声明的参数必须位于最后位置

2.      声明的参数必须是Variant数据类型

3.      Application的Intersect的作用是让函数只计算数据区域与参数所有代码区域的重叠去,防止整列,整行或者整个工作表作为参数造成死机,但它同事也带来了一个缺点参数智能引用本工作表的区域,一用其他工作表或者工作簿区域时,将忽略

                     vi.             开发带具有三个参数切第三个为可选的function过程

声明方式:function 三餐(条件区 as range,颜色单元格 as range,optional 统计区)

收获:

计算单元格背景色必须使用Color,不能用ColorIndex。在2003中可以使用。但在2010中不能使用

Range.Resize(num1,num2)属性用于调整指定区域的大小。 参数1表示新区域的行数,新区域中的列数,如果忽略。则不变

ReDim Preserve array(1 To 2)没找到一个目标就需要重置数组的大小,且重置时需要保留原数组的值,所以循环中必须加入 ReDim Preserve 来声明数组

Transpose(数组)  将横向数组专置为纵向数组

Vlookup 函数  只能返回一个符合条件的目标值

三、编写函数的帮助

当你在模块或者其他地方编写了函数,需要让用户使用的时候,用户双击进去,帮助信息空白。那么给用户带来了很大的不便,所以需要编写函数的帮助信息

Application.MacroOptions方法编写帮助信息

Application.MacroOptions(macro,Description,HasMenu,MenuText,HasShortcutKey,ShortcutKey,Category,StatusBar,HelpCountextId,HelpFile)

Macro      宏的名称或用户定义的函数的名称

Description      宏的描述

hasMenu          忽略该参数

MenuText         忽略该参数

HasShortcutKey       如果为true,则为宏指定一个快捷键,必须指定shortcutKey。如果该参数为false,则不为宏指定快捷键。如果宏已经有快捷键,如果指定false就失效

ShortcutKey     如果上面参数为true,必须指定快捷键

Category           一个指定现有的宏函数类别的整数,如果提供了一个字符串,它将作为类别名称显示在插入函数的对话框中。如果此类别名称未使用过,则用该名称定义一个新的类别,如果使用的类别名称与某个内置名称相同,将把用户定义的函数映射到该内置类别

statusBar    宏的状态栏文本

HelpCountextId        一个指定分配给宏帮助主题上下文id的整数

HelFIie               包含HelpContextId定义的帮助主题的帮助文件名

ArgumentDescriptions             函数参数 对话框中显示的参数的描述

 

四、总结

Function过程即自定义函数,根据工作需要可以开发自己专用的函数

 

对于函数的运算速度,内部的工作表函数一定快于用户自定义的函数。

 

开发自定义函数的时候,应该尽量给用户一些可选项,使函数运算更简单,公式也更简短。参数可选的概念

 

对于某些运算结果,如果可以返回多个结果,应尽可能将所有格式全部罗列出来,让用户选择。例如本次的日期函数

 

对于有多个结果的函数,应将函数声明为数组,将所有结果显示给用户,但为了体现灵活性,同事需要指定一种默认显示的值。例如自定义函数VlookupCol。

 

为了让用户自定义的函数在任何工作簿都可以使用,应将工作簿为加载宏文件。并对齐加载或者至于自启动文件夹。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值