VBA|比较怪异的一些语法规则

C、C++、Java、python等一众流行编程语言,其语法规则有较大的相似性。

唯独VB、VBA的一些语法规则比较怪异,一枝独特。

0 变量声明与数据类型

VBA使用关键字Dim和As声明变量,类型后置,As和后面的类型可选。

Sub ExampleDeclaration()
    Dim a As Integer
    Dim b As Long
    Dim c As Single
    Dim d As Double
    Dim e As String
    Dim f As Variant
End Sub

不鼓励使用类型提示(Type Hints)。由于历史和向后兼容性的原因,下面是一些演示。建议改用As[DataType]语法。

Public Sub ExampleDeclaration()
    Dim someInteger% '
    Dim someLong& 
    Dim someDecimal@
    Dim someSingle!
    Dim someDouble#
    Dim someString$
    Dim someLongLong^
End Sub

1 数组声明和使用

  • Option Base 0 :数组索引值从0开始
  • Option Base 1 :数组索引值从1开始
  • Dim MyArray(10) :声明一个数组变量,10是最大的可用的数组索引值
  • MyArray(5) = 101 :给数组的元素赋值
  • Dim Data(10,5) :声明一个二维数组变量
  • Data(1,1) = "A001" :给数组元素赋值
  • Dim cArr(-11 To 20, 1 To 3) As String :声明一个数组,定义数组索引值的上下界
  • Dim dArr() As String :声明动态数组
  • ReDim dArr(0 To 5, 1 To 2) :改变动态数组的尺寸默认把原数据清除。如果保留原来的数据,必须加上参数
  • Preserve:使用Preserve参数时只能改变最后一位的大小
  • If UBound(vTemp) = -1 Then:判断数组变量vTemp是否为空数组
  • End If Erase MyArrar, Data Erase语句清除数组元素,释放变量占用的空间

2 对象变理的特殊处理

使用set来定义对象变量(给对象变量赋值);

Dim Conn
Dim Reco
Set Conn = CreateObject("ADODB.Connection")
Set Rec1 = CreateObject("ADODB.Recordset")

后面一般都需要:

Set Conn = Nothing
Set Reco = Nothing

它们到底起到什么作用?释放内存?

当一个对象实例化时,系统自动实例化一个对象,然后接受引用,每引用一次,则计数器加一,每=nothing一次,则计数器减一,当计数器为0时,系统有可能释放对象的实例。

准确地说是减少对象引用计数,并使变量指向nothing,当对象的引用计数为0时,系统(注意不是“你”)才会释放对象,只是一般情况只用一个变量指向对象,所以也可直接理解为释放对象,不过还是要注意差别的。

Set XXX = Nothing ' 这并不是释放那个对象, 它只是断开这个变量与对象本身的引用, 当那个对象的引用计数变成 0, 它就会被释放掉。

这个是释放掉一个对象实例,并且引用计数-1。

如果一个对象被一个以上变量引用, Set XXX = Nothing(其中一个) 后那个对象依然存在。

3 函数版本

在 VB6 中,字符串函数有两个版本,分别是带 $ 的和不带 $ 的。带 $ 的还是与老版本相同,不带 $ 的是以 Unicode 方式工作的。

VB中函数名后的“$”符号什么意思?

Left是返回Variant数据类型,而Left$是返回String数据类型,后者要块。

一些解释是说对旧版的支持。

4 函数参数传递

引用传递ByRef:

Public Sub Test()
    Dim foo As Long
    foo = 42
    DoSomething foo
    Debug.Print foo
End Sub

Private Sub DoSomething(ByRef foo As Long)
    foo = foo * 2
End Sub

5 函数调用

过程在Excel中可以通过菜单、工具栏、按钮、快捷键等方式直接调用,函数可以在工作表的公式中如同内置函数一样调用。

过程和函数在模块内可以直接调用,也可以使用OnTimeOnKey方法间接调用

对许多内建函数、语句和方法,Visual Basic 提供了命名参数方法来快捷传递参数值。对命名参数,通过给命名参数赋值,就可按任意次序提供任意多参数。为此,键入命名参数,其后为冒号、等号和值 (MyArgument := "SomeValue") ,可以按任意次序安排这些赋值,它们之间用逗号分开

在调过程或方法调用时,参数是否使用括号?视是否使用其参数而定:

Sub test()
    Dim ws1 As Worksheet, str1 As String
    Application.InputBox Prompt:="请输入删除的工作表名称:"  '在调用不使用返回值的函数时不使用括号
    str1 = Application.InputBox(Prompt:="请输入删除的工作表名称:")   '在调用使用返回值的函数时才应使用括号
End Sub

更多细节参照:VBA|过程或方法内部的直接或间接调用与相对怪异的语法格式

6 错误处理和流程转向

On Error 语句启动一个错误处理程序并指定该子程序在一个过程中的位置,也可用来禁止一个错误处理程序。该语句共有以下3 种语法格式。

On Error GoTo line:启动错误处理程序,且该例程从必要的line 参数中指定的line开始。line 参数可以是任何行标签或行号。如果发生一个运行时错误,则控件会跳到line,激活错误处理程序。指定的line 必须在一个过程中,这个过程与On Error语句相同,否则会发生编译时间错误。

On Error Resume Next:说明当一个运行时错误发生时,控件转到紧接着发生错误的语句之后的语句,并在此继续运行。访问对象时要使用这种形式而不使用OnError GoTo。

On Error GoTo 0:禁止当前过程中任何已启动的错误处理程序。

7 集合和字典

7.1 Collection

Collection相当于其它语言的set:

Public Sub Example()
    Dim foo As New Collection
    With foo
        .Add "One"
        .Add "Two"
        .Add "Three"
        .Add "Four"
    End With
    Debug.Print foo.Count
End Sub

7.2 Dictionary

Dictionary相当于其它语言的map。

'Populate, enumerate, locate and remove entries in a dictionary that was created
'with late binding
Sub iterateDictionaryLate()
    Dim k As Variant, dict As Object
    Set dict = CreateObject("Scripting.Dictionary")
    dict.CompareMode = vbTextCompare 'non-case sensitive compare model
    'populate the dictionary
    dict.Add Key:="Red", Item:="Balloon"
    dict.Add Key:="Green", Item:="Balloon"
    dict.Add Key:="Blue", Item:="Balloon"
    'iterate through the keys
    For Each k In dict.Keys
        Debug.Print k & " - " & dict.Item(k)
    Next k
    'locate the Item for Green
    Debug.Print dict.Item("Green")
    'remove key/item pairs from the dictionary
    dict.Remove "blue" 'remove individual key/item pair by key
    dict.RemoveAll 'remove all remaining key/item pairs
End Sub

8 代码延迟与DoEvents

以下代码将延时10 秒:

st = Timer
Do While Timer < st + 10
    DoEvents
Loop

以上代码首先保存系统的一个时间,再通过循环反复检测当前时间是否超过预调的时间,如果未超过,则一直执行该循环,直到超过为止,这样就达到了延时的目的。

在以上代码的循环体中包含了DoEvents 函数,该函数用来转让控制权,以便让操作系统处理其他的事件。

如果以上代码不包含DoEvents 函数,则计算机在执行这段延时程序时,将不允许在Excel 中进行其他操作,直到延时循环执行结束。

DoEvents 函数

转让控制权,以便让操作系统处理其它的事件。

9 代码行号

VBA supports legacy-style (e.g. QBASIC) line numbers. The Erl hidden property can be used to identify the line number that raised the last error. If you're not using line numbers, Erl will only ever return 0.

Sub DoSomething()
    10 On Error GoTo 50
    20 Debug.Print 42 / 0
    30 Exit Sub
    40
    50 Debug.Print "Error raised on line " & Erl ' returns 20
End Sub

10 标准模块

标准模块只包含过程、类型以及数据的声明和定义。在Visual Basic 的早期版本中,将标准模块看作代码模块。

Dim arr
arr = Array(0.1, 0.2, 0.5, 1, 2, 5) // 数组列表
For i = 1 To 6  '越界会直接提示出错
   Sheets(1).Cells(1, i) = arr(i - 1)
Next

11 层次对象模型

Excel VBA是基于对象的编程语言。其本身有丰富的层次对象模型,也可以引入外部应用的对象模型:

这些外部对象库当然包括自己的全家桶。

微软公司提供的自动化技术可以将某一个应用程序的功能当作一系列的对象提供给其他的外部应用程序,这个外部应用程序就可以使用这些对象,这个过程被称为自动化(Automation)。自动化就是通过一个应用程序来控制另外一个应用程序的处理过程。

绝大多数支持自动化的应用程序都提供一个对象库。该对象库为控制器应用程序提供了服务器应用程序中可以使用的对象的有关信息。如使用自动化技术来控制Word,就是用Word 作为服务器应用程序,因而需要在Excel 中引用Word对象。

12 引用样式

在VBA 程序中,可使用Range("A1:C3")样式引用单元格区域。如果需要动态选择单元格区域,其A1 引用样式不方便随程序动态变化,这时可对Range 对象的Range 属性用以下格式进行处理:

表达式.Range(Cell1, Cell2)

式中,Cell1 和Cell2 可分别用行列索引号指定一个单元格,创建的Range 对象是以这两个单元格为对角所形成的区域。创建动态单元格区域可使用以下几种方式:

Range("A" & i)
Range("A" & i & ":C" & i)
Range(Cells(i, 2), Cells(i, 7))

同时在“Sheet1”、“Sheet2”和“Sheet3”三个工作表中的“A1:E1”区域设置边框线。

Sub set_line()
    Dim rng1 As Range
    Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Select
    Set rng1 = Range("A1:E1")
    rng1.Borders.LineStyle = xlDouble
    Set rng1 = Nothing
End Sub

返回R1C1 样式的引用:

Sub GetAddress()
    Dim rng1 As Range
    Dim str1 As String, strTitle As String
    Set rng1 = Range("BB123") 'R123C54
    Debug.Print rng1.Address(ReferenceStyle:=xlR1C1)
End Sub

引用方式A1和R1C1转换

'A1转R1C1:
function TransferFromat(byval rangeAdd as string) as string
     dim str as string
     str =Application.ConvertFormula(rangeAdd , xlA1, xlR1C1)
    TransferFromat=str 
end function
'R1C1转A1:
function TransferFromat(byval rangeAdd as string) as string
     dim str as string
     str =Application.ConvertFormula(rangeAdd ,xlR1C1, xlA1 )
    TransferFromat=str 
end function
Application.ReferenceStyle = xlA1

Application.ReferenceStyle = xlR1C1

ref

吴永佩,成丽君 《征服Excel VBA:让你工作效率倍增的239 个实用技巧 》

-End-

举报
评论 0