Excel VBA 学习总结 – 实战之惑

  VBA中很多的功能可以用内置的函数完成,其它的可以自己写函数完成。下面几点就是我在实战中遇到比较多的,而且带有一定困惑性的典型问题。

一、返回列的名字

  这是个最简单的问题,但是有时候还是很需要的,方法比较简单,就是通过Address获取列的名字,比如“A”,“AB”等。

PrivateFunctioncolumnHeader(TargetAsRange)AsStringcolumnHeader=Left$(Right$(Target.Address,Len(Target.Address)-1),InStr(1,Right$(Target.Address,Len(Target.Address)-1),”$”)-1)EndFunction

二、寻找实际使用的最后一行

  这个问题在实际中经常遇到,而且实现的方式也多种多样。

使用ExecuteExcel4Macro实现  在Excel VBA中,内置函数ExecuteExcel4Macro用于执行一些Excel 4.0中的一些函数。其中有一个特殊的函数是返回Sheet使用的最后一行的,使用很简单,如下所示:

SubShowLastLine()MsgBoxExecuteExcel4Macro(“GET.DOCUMENT(10)”)EndSub

Application.ExecuteExcel4Macro的用法说明:作用:执行一个 Microsoft Excel 4.0 宏函数,然后返回此函数的结果。返回结果的类型取决于函数的类型。 语法:ExecuteExcel4Macro(String)参数:String,一个不带等号的 Microsoft Excel 4.0 宏语言函数。所有引用必须是像 R1C1 这样的字符串。如果 String 内包含嵌套的双引号,则必须写两个。例如,要运行宏函数 =MID(“sometext”,1,4),String 必须为 “MID(“”sometext””,1,4)”。 返回值:Variant说明:Microsoft Excel 4.0 宏不在当前工作簿或工作表的环境中求值。也就是说所有的引用都应该是外部引用,而且需要明确指定工作簿名。例如,要在 Book1 中执行 Microsoft Excel 4.0 宏“My_Macro”,必须使用“Book1!My_Macro()”。如果不指定工作簿名,此方法将失效。示例:本示例对工作表 Sheet1 上的 C3 单元格执行 GET.CELL(42) 宏函数,然后在一个消息框中显示结果。GET.CELL(42) 宏函数返回当前窗口左边界到活动单元格的左边之间的水平距离。Visual Basic 中没有与此宏函数直接等价的函数。

Worksheets(“Sheet1”).ActivateRange(“C3”).SelectMsgBoxExecuteExcel4Macro(“GET.CELL(42)”)

使用End属性  在ExcelVBA中,使用End(xlUp)查找最后一行是最常使用且最为简单的方法,它假设要有一列总包含有数据(数字、文本和公式等),并且在该列中最后输入数据的单元格的下一行不会包含数据,因此不必担心会覆盖掉已有数据。但该方法有两个缺点:(1) 仅局限于查找指定列的最后一行。(2) 如果该列中最后一行被隐藏,那么该隐藏行将被视作最后一行。因此,在最后一行被隐藏时,其数据可能会被覆盖。但该列中间的隐藏行不会影响查找的结果。

PublicFunctionLastRowInColumn(ColumnAsString)AsLongLastRowInColumn=Range(Column&Rows.Count).End(xlUp).RowEndFunction

使用Find方法  Find方法在当前工作有数据中进行查找,不需要指定列,也可以确保不会意外地覆盖掉已有数据。其中,参数LookIn指定所查找的类型,有三个常量可供选择,即xlValues、xlFormulas和xlComments。(1) 常量xlFormulas将包含零值的单元格作为有数据的单元格。(当设置零值不显示时,该单元格看起来为空,但该参数仍将该单元格视为有数据的单元格)(2) 常量xlValues将包含零值的单元格(如果设置零值不显示时)作为空白单元格,此时,若该单元格在最后一行,则Find方法会认为该单元格所在的行为空行,因此,该单元格中的内容可能会被新数据所覆盖。(在Excel中,选择菜单“工具”——“选项”,在打开的“选项”对话框中,选择“视图”选项卡,将其中的“零值”前的复选框取消选中,则工作表中的零值都不会显示)  如果在参数LookIn中使用常量xlValues的话,还存在一个问题是:如果您将最后一行隐藏,则Find方法会认为倒数第二行是最后一行,此时您在最后一行的下一行输入数据,则会将实际的最后一行的数据覆盖。

PublicFunctionLastRow()AsLong ‘使用常量xlFormulas,因为常量xlValues会忽略隐藏的最后一行LastRow=Cells.Find(“*”,LookIn:=xlFormulas,SearchDirection:=xlPrevious).RowEndFunction

Find方法中,参数LookIn的默认值为xlFormulas。

使用UsedRange属性  UsedRange方法可用于在工作表中已使用区域查找最后一行,该区域包括可能以前使用过的任何单元格,但现在其中的数据被删除了,比如目前的工作表中只有第1行至第5行共5行,其它行都无数据,但在第6行中有些单元格以前使用过(可能仅仅格式化或内容清除了,总之该行现在不含有数据),那么第6行也包含在该已使用的区域中。此外,如果最后一行被隐藏,那么会将因此,使用该方法查找最后一行是无规律且不可靠的,它通常可能会得到预料不到的结果。

PublicFunctionLastUsedRow()AsLongWithActiveSheetLastUsedRow=.UsedRange.Rows.Count+.UsedRange.Row-1EndWithEndFunction

使用SpecialCells方法  也可以用SpecialCells方法实现查找最后一行,其常量xlCellTypeLastCell代表在”已使用区域”中的最后一个单元格,与UsedRange属性稍有不同的是,当您在最后一行中输入数据后,又将其删除,则此数据所在的单元格也包含在已使用的区域中,并且如果最后的行被隐藏,则将可见行的最后一行当作最后一行。

PublicFunctionLastUsedRow()AsLongLastUsedRow=Cells.SpecialCells(xlCellTypeLastCell).RowEndFunction

SpecialCells方法用于查找指定类型的值,其语法为SpecialCells(Type,Value),有两种主要的使用方式:(1) 若参数Type仅考虑常量,则在查找时会忽略和覆盖由公式生成的任何数据。(2) 若参数Type仅考虑由公式生成的数据,则在查找时会忽略和覆盖任何常量数据。  如果参数Type是xlCellTypeConstants或者是xlCellTypeFormulas,则Value参数可使用常量决定哪种类型的单元格将被包含在结果中,这些常量值能组合而返回多个类型,其缺省设置是选择所有的常量或公式,而不管是何类型,可使用下面四个可选的常量:1) xlTextValues(包含文本); 2) xlNumbers(包含数字);3) xlErrors(包含错误值); 4) xlLogical(包含逻辑值);  我们可以使用SpecailCells方法去找到其它特定类型的单元格所在的最后一行,下面是这些常量的一个完整的列表:XlCellTypeAllFormatConditions (任何格式的单元格)XlCellTypeAllValidation (带有数据有效性的单元格)XlCellTypeBlanks (所使用区域中的空白单元格)XlCellTypeComments (包含有批注的单元格)XlCellTypeConstants (包含有常量的单元格)XlCellTypeFormulas (包含有公式的单元格)XlCellTypeLastCell (已使用区域中的最后一个单元格(看下面))XlCellTypeSameFormatConditions (有相同格式的单元格)XlCellTypeSameValidation (有相同数据有效性条件的单元格)XlCellTypeVisible (工作表中所有可见的单元格)

使用CurrentRegion属性  Range对象的CurrentRegion属性返回代表单元格所在的当前区域,即四周有空行的独立区域,因此,可使用此属性查找当前区域的最后一行。但是使用其查找最后一行的一个缺点是,必须首先选取当前区域,然后进行查找。

三、自定义类型扩展

  VBA中扩充基本类型的基本手段就是自定义类型,主要有两种方式。

1. 定义Type

  使用Type关键字可以定义一些简单的自定义类型,这些类型使用起来就像基本类型一样使用,直接定义和赋值。例如:

PublicTypeEmployeeNameAsStringAddressAsStringSalaryAsDoubleEndTypeDimManagerAsEmployeeManager.Name=”JoeSmith”Manager.Address=”123MainStreet”Manager.Salary=40000

  Type定义和使用都很简单,但是它只是一种静态的数据结构,无法完成很多高级的功能;它的显著缺点如下:

(1).无法创建Type的实例,可以存放到数组中,但是无法存放到Collection与Dictionary中。

(2).无法控制成员的有效范围,也就是无法验证成员的值是合法的。

(3).只有数据,无法去定义行为。

2. 定义Class

  正是由于Type简单但是难以胜任复杂的情景,所以当需要一些负责的处理数据的场景时,往往需要定义Class这种更强大的扩展。定义Class的方式也很简单,直接在工程中插入一个Class Module就可以了,可以在属性窗口中设置Class的名字。下面是示例:

PrivatepNameAsStringPrivatepAddressAsStringPrivatepSalaryAsDoublePublicPropertyGetName()AsStringName=pNameEndPropertyPublicPropertyLetName(ValueAsString)pName=ValueEndPropertyPublicPropertyGetAddress()AsStringAddress=pAddressEndPropertyPublicPropertyLetAddress(ValueAsString)pAddress=ValueEndPropertyPublicPropertyGetSalary()AsDoubleSalary=pSalaryEndPropertyPublicPropertyLetSalary(ValueAsDouble)IfValue>0ThenpSalary=ValueElse’appropriateerrorcodehereEndIfEndProperty’使用例子DimEmpAsCEmployeeSetEmp=NewCEmployeeEmp.Name=”JoeSmith”Emp.Address=”123MainStreet”Emp.Salary=40000

Class是更为高级的对象,它带来的良好的封装性,也带来了一定的复杂性。所以只应该对那些具有行为,重用性高的数据建模成Class。

Class需要使用New关键字去创建新实例,而且需要使用Set关键字去赋值。

使用Type经常会遇到(传递参数,存放到集合等等)的一个错误是”Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions.”。这个时候,需要定义一个Class去完成相关功能,而不是去定义一个Type。

别小看任何人,越不起眼的人。往往会做些让人想不到的事。

Excel VBA 学习总结 – 实战之惑

相关文章:

你感兴趣的文章:

标签云: