Excel-VBA教程完全版





                                                                 目                     录 






                               ...................................................................................................................1 


一、VBA语言基础 ......................................................................................................................................................................................................................................11 






    第一节 标识符....................................................................................................................................1 


    第二节 运算符....................................................................................................................................1 


    第三节 数据类型................................................................................................................................1 


    第四节 变量与常量............................................................................................................................1 


    第五节 数组........................................................................................................................................2 


    第六节 注释和赋值语句....................................................................................................................2 


    第七节 书写规范................................................................................................................................2 


    第八节 判断语句................................................................................................................................2 


    第九节 循环语句................................................................................................................................3 


    第十节 其他类语句和错误语句处理................................................................................................4 


    第十一节 过程和函数........................................................................................................................4 


        一.Sub过程 ................................................................. 4 


        二.Function函数 ............................................................ 5 


        三.Property属性过程和Event事件过程 ......................................... 5 


    第十二节内部函数 .............................................................................................................................5 


        一.测试函数 ................................................................ 5 


        二.数学函数 ................................................................ 5 


        三.字符串函数 .............................................................. 5 


        四.转换函数 ................................................................ 6 


        五.时间函数 ................................................................ 6 


    第十三节 文件操作............................................................................................................................6 


        文件 ........................................................................ 6 


        删除 ........................................................................ 6 


        打开 ........................................................................ 6 


        读入 ........................................................................ 7 


        写入 ........................................................................ 7 


        关闭 ........................................................................ 7 


        其他文件函数 ................................................................ 7 






                                                           .....................................................................................1 


二、VISUAL BASIC程序设计网络教学 ..........................................................................................................................................................................11 






                              .................................................................................................................1 


第一课 VBA是什么 ..................................................................................................................................................................................................................................11 






    1.1 VBA是什么....................................................................................................................................1 


    1.2 EXCEL环境中基于应用程序自动化的优点................................................................................1 


    1.3 录制简单的宏..............................................................................................................................1 


    1.4 执行宏..........................................................................................................................................2 


    1.5 查看录制的代码..........................................................................................................................2 


    1.6 编辑录制的代码..........................................................................................................................3 


    1.7 录制宏的局限性..........................................................................................................................3 


    1.8 小结..............................................................................................................................................3 






                                    ............................................................................................................3 


第二课 处理录制的宏 ........................................................................................................................................................................................................................33 






    2.1 为宏指定快捷键..........................................................................................................................3 


    2.2 决定宏保存的位置......................................................................................................................4 


    2.3 个人宏工作簿..............................................................................................................................4 


        2.3.1 保存宏到个人宏工作簿 .................................................. 4 


        2.3.2 使用并编辑个人宏工作簿中的宏 .......................................... 4 


    2.4 将宏指定给按钮..........................................................................................................................4 


    2.5 将宏指定给图片或其他对象......................................................................................................5 


    2.6 小结..............................................................................................................................................5 






                             ...................................................................................................................5 


第三课 学习控件 ......................................................................................................................................................................................................................................55 




----------------------- Page 2-----------------------


    3.1 EXCEL开发过程简介....................................................................................................................5 


    3.2 认识不同的控件..........................................................................................................................5 


    3.3 向工作表添加控件......................................................................................................................6 


    3.4 设置控件的特性..........................................................................................................................6 


    3.5 给控件命名..................................................................................................................................6 


    3.6 使用用户窗体..............................................................................................................................6 


    3.7 疑难解答......................................................................................................................................7 






                                                   ..............................................................................................7 


第四课 理解变量和变量的作用 ............................................................................................................................................................................................77 






    4.1 代码存在的位置:模块..............................................................................................................7 


    4.2 对模块的概览..............................................................................................................................7 


        4.2.1 创建过程 .............................................................. 8 


        4.2.2 运行宏 ................................................................ 9 


    4.3 保存对模块所做的改变..............................................................................................................9 


    4.4 变量..............................................................................................................................................9 


        4.4.1 变量的数据类型 ........................................................ 9 


        4.4.2 用Dim语句创建变量(声明变量) .......................................... 10 


        4.4.3 变量命名的惯例 ....................................................... 10 


        4.4.4 使用数组 ............................................................. 10 


        4.4.5 变量赋值 ............................................................. 11 






                                                                  ...................................................................................11 


第五课 利用VBA设置工作表使用权限 ......................................................................................................................................................................1111 






    1.使用WITH语句。 .......................................................................................... 


    2.使用对象变量。 ......................................................................................... 


    方法 3:减少对象的激活和选择 .................................................................... 


    方法 4:关闭屏幕更新 .................................................................................... 






                                                        ............................................................................................12 


第六课 提高EXCEL中VBA的效率 ........................................................................................................................................................................................1122 






    方法 1:尽量使用VBA原有的属性、方法和WORKSHEET函数............................................................12 


    方法 2:尽量减少使用对象引用,尤其在循环中.........................................................................12 


        1.使用With语句。 .......................................................... 12 


        2.使用对象变量。 .......................................................... 12 


        3.在循环中要尽量减少对象的访问。 .......................................... 13 


    方法 3:减少对象的激活和选择 ....................................................................................................13 


    方法 4:关闭屏幕更新 ....................................................................................................................13 






                                                            .......................................................................................13 


第七课 如何在EXCEL里使用定时器..............................................................................................................................................................................1133 






                                                                                           ...........................................................15 


三、学习微软 EXCEL 2002 VBA 编程和XML,ASP技术......................................................................................................................1155 






                                                                         ...........................................................................15 


第一章 电子表格自动化简介和了解宏命令......................................................................................................................................................1155 






    1 了解宏 ............................................................................................................................................15 


    2 宏命令的普通应用 ........................................................................................................................15 


    3 写宏之前的计划 ............................................................................................................................16 


    4 录制宏 ............................................................................................................................................17 


    5 运行宏 ............................................................................................................................................18 


    6 修改宏代码 ....................................................................................................................................19 


    7 添加注释 ........................................................................................................................................21 


    8 分析宏代码 ....................................................................................................................................22 


    9 清除宏代码 ....................................................................................................................................23 


    10 测试修改好的宏 ..........................................................................................................................24 


    11 两个层面运行宏的方法 ..............................................................................................................24 


    12 完善你的宏代码 ..........................................................................................................................25 


    13 重新命名宏 ..................................................................................................................................27 


    14 运行宏的其它方法 ......................................................................................................................27 




----------------------- Page 3-----------------------


    15 使用键盘快捷键运行宏 ..............................................................................................................27 


    16 通过菜单运行宏 ..........................................................................................................................28 


    17 通过工具栏按钮运行宏 ..............................................................................................................30 


    18 通过工作表里面的按钮运行宏 ..................................................................................................31 


    19 保存宏 ..........................................................................................................................................32 


    20 打印宏 ..........................................................................................................................................32 


    21 保存宏在个人宏工作簿 ..............................................................................................................32 


    22 打开含有宏的工作簿 ..................................................................................................................34 


    23VB编辑窗口 ...................................................................................................................................35 


    24 了解工程浏览窗口 ......................................................................................................................35 


    25 了解属性窗口 ..............................................................................................................................36 


    26 了解代码窗口 ..............................................................................................................................36 


    27 VB编辑器里的其它窗口 ..............................................................................................................38 


    28 接下来…… ..................................................................................................................................39 






                                  ..............................................................................................................39 


第二章 VBA 第一步............................................................................................................................................................................................................................3399 






    1 了解指令,模块和过程 ................................................................................................................39 






    2 VBA工程命名..................................................................................................................................39 


    3 模块重命名 ....................................................................................................................................40 


    4 从其它工程调用过程 ....................................................................................................................41 


    5 了解对象,属性和方法 ................................................................................................................42 


    6 学习对象,属性和方法 ................................................................................................................43 


    7 句法和文法 ....................................................................................................................................45 


    8 打断很长的VBA语句 ......................................................................................................................47 


    9 了解VBA错误 ..................................................................................................................................47 


    10 查找帮助 ......................................................................................................................................49 


    11 语法和编程快捷助手 ..................................................................................................................50 


    12 属性/方法列表 ............................................................................................................................51 


    13 常数列表 ......................................................................................................................................51 


    14 参数信息 ......................................................................................................................................52 


    15 快速信息 ......................................................................................................................................52 


    16 自动完成关键字 ..........................................................................................................................52 


    17 缩进/凸出 ....................................................................................................................................53 


    18 设置注释块/解除注释块 ............................................................................................................53 


    19 使用对象浏览器 ..........................................................................................................................53 


    20 使用VBA对象库 ............................................................................................................................58 


    21 用对象浏览器来定位过程 ..........................................................................................................59 


    22 使用立即窗口 ..............................................................................................................................59 


    23 获取立即窗口里的信息 ..............................................................................................................61 


    24 学习对象 ......................................................................................................................................62 


    25 电子表格单元格操作 ..................................................................................................................62 


    26 使用RANGE属性..............................................................................................................................62 


    27 使用CELLS属性..............................................................................................................................62 


    28 使用OFFSET属性 ............................................................................................................................63 


    29 选择单元格的其它方法 ..............................................................................................................64 


    30 选择行和列 ..................................................................................................................................64 


    31 获取工作表信息 ..........................................................................................................................65 


    32 往工作表输入数据 ......................................................................................................................65 


    33 返回工作表中的信息 ..................................................................................................................65 


    34 单元格格式 ..................................................................................................................................66 


    35 移动,复制和删除单元格 ..........................................................................................................66 


    36 操作工作簿和工作表 ..................................................................................................................67 


    37 操作窗口(WINDOWS)...................................................................................................................67 


    38 管理EXCEL应用程序......................................................................................................................68 




----------------------- Page 4-----------------------


    39 接下来…… ..................................................................................................................................68 






                                                                 .....................................................................................69 


第三章 了解变量,数据类型和常量 ..........................................................................................................................................................................6699 






    1 保存VBA语句的结果 ......................................................................................................................69 


    2 变量是什么 ....................................................................................................................................69 


    3 数据类型 ........................................................................................................................................69 


    4 如何产生变量 ................................................................................................................................70 


    5 如何声明变量 ................................................................................................................................71 


    6 明确变量的数据类型 ....................................................................................................................72 


    7 变量赋值 ........................................................................................................................................73 


    8 强制声明变量 ................................................................................................................................75 


    9 了解变量范围 ................................................................................................................................76 


    10 过程级别(当地)变量 ..............................................................................................................76 


    11 模块级别变量 ..............................................................................................................................77 


    12 工程级别变量 ..............................................................................................................................77 


    13 变量的存活期 ..............................................................................................................................78 


    14 了解和使用静态变量 ..................................................................................................................78 


    15 声明和使用对象变量 ..................................................................................................................79 


    16 使用明确的对象变量 ..................................................................................................................80 


    17 查找变量定义 ..............................................................................................................................80 


    18 在VB过程里面使用常量 ..............................................................................................................80 


    19 内置常量 ......................................................................................................................................81 


    20 接下来…… ..................................................................................................................................82 






                                                           ..........................................................................................82 


第四章 VBA过程:子程序和函数 ....................................................................................................................................................................................8822 






    1.关于函数过程 ...............................................................................................................................82 


    2.创建函数过程 ...............................................................................................................................82 


    3.执行函数过程 ...............................................................................................................................84 


    4.从工作表里运行函数过程 ...........................................................................................................84 


    5.从另外一个VBA过程里运行函数过程 .........................................................................................85 


    6.传递参数 .......................................................................................................................................86 


    7.明确参数类型 ...............................................................................................................................87 


    8.按地址和按值传递参数 ...............................................................................................................88 


    9.使用可选的参数 ...........................................................................................................................88 


    10.定位内置函数 .............................................................................................................................89 


    11.使用MSGBOX函数...........................................................................................................................90 


    12.MSGBOX函数的运行值 ...................................................................................................................94 


    13.使用INPUTBOX函数........................................................................................................................95 


    14.数据类型转变 .............................................................................................................................96 


    15.使用INPUTBOX方法........................................................................................................................97 


    16.使用主过程和子过程 ...............................................................................................................100 


    17.接下来…… ...............................................................................................................................102 






                                           ......................................................................................................102 


第五章 基于VBA做决定 ............................................................................................................................................................................................................110022 






    1.关系和逻辑运算符 .....................................................................................................................102 






    2.IF…THEN语句...............................................................................................................................103 


    3.基于多于一个条件的决定 .........................................................................................................105 


    4.THE IF…THEN…ELSE语句 .............................................................................................................106 


    5.IF…THEN…ELSEIF语句 ................................................................................................................108 


    6.嵌套的IF…THEN语句...................................................................................................................110 


    7.SELECT CASE语句...........................................................................................................................110 


    8.和CASE子句一起使用IS ...............................................................................................................112 


    9.确定CASE子句里数值的范围 ......................................................................................................113 


    10.在CASE子句里确定多个表达式.................................................................................................114 




----------------------- Page 5-----------------------


    11.接下来… ...................................................................................................................................114 






                                               ...................................................................................................114 


第六章 在VBA中重复操作......................................................................................................................................................................................................111144 






    1.DO LOOPS: DO…WHILE和DO…UNTIL................................................................................................114 


    2.观察过程执行 .............................................................................................................................117 


    3.WHILE…WEND循环..........................................................................................................................118 


    4.FOR…NEXT 循环 ...........................................................................................................................119 


    5.FOR EACH…NEXT循环.....................................................................................................................120 


    7.提前跳出循环 .............................................................................................................................121 


    8.循环嵌套 .....................................................................................................................................122 


    9.接下来… .....................................................................................................................................122 






                                                                       ..........................................................................122 


第七章 利用VBA数组管理数据清单和表格 ....................................................................................................................................................112222 






    1.了解数组 .....................................................................................................................................123 






    2.声明数组 .....................................................................................................................................124 


    3.数组的上界和下界 .....................................................................................................................124 


    4.在VBA过程里使用数组 ...............................................................................................................124 


    5.数组和循环语句 .........................................................................................................................125 


    6.使用二维数组 .............................................................................................................................127 


    7.静态和动态数组 .........................................................................................................................128 


    8.数组函数 .....................................................................................................................................129 


    9.ARRAY函数.....................................................................................................................................130 


    10.ISARRAY函数 ...............................................................................................................................130 


    11.ERASE函数...................................................................................................................................131 


    12.LBOUND函数和UBOUND函数 ..........................................................................................................131 


    13.数组中的错误 ...........................................................................................................................132 


    14.数组作为参数 ...........................................................................................................................134 


    15.接下来… ...................................................................................................................................134 






                                                                .....................................................................................134 


第八章 利用VBA操纵文件和文件夹..........................................................................................................................................................................113344 






    1.获取当前文件夹的名称(CURDIR函数) ...................................................................................135 


    2.更改文件或文件夹名称(NAME函数).......................................................................................135 


    3.检查文件或文件夹是否存在(DIR函数) ................................................................................136 


    4.获得文件修改的日期和时间(FILEDATETIME函数) .................................................................137 


    5.获得文件大小(FILELEN函数) .................................................................................................138 


    6.返回和设置文件属性(GETATTR函数和SETATTR函数) .............................................................138 


    7.更改缺省文件夹或驱动器(CHDIR语句和CHDRIVE语句).........................................................139 


    8.创建和删除文件夹(MKDIR语句和RMDIR语句)........................................................................140 


    9.复制文件(FILECOPY语句)........................................................................................................140 


    10.删除文件(KILL语句) ............................................................................................................142 


    11.从文件读取和写入数据(INPUT/OUTPUT)...............................................................................142 


    12.文件访问类型 ...........................................................................................................................142 


    13.使用顺序文件 ...........................................................................................................................143 


    14.读取储存于顺序文件里的数据 ...............................................................................................143 


    15.逐行读取文件 ...........................................................................................................................143 


    16.从顺序文件中读取字符 ...........................................................................................................144 


    17.读取分隔文本文件 ...................................................................................................................145 


    18.往顺序文件里写数据 ...............................................................................................................146 


    19.使用WRITE # 和PRINT # 语句....................................................................................................147 


    20.操作随机文件 ...........................................................................................................................148 


    21.创建用户定义的数据类型 .......................................................................................................148 


    22.操作二进制文件 .......................................................................................................................152 


    23.操作文件和文件夹的时髦方法 ...............................................................................................153 


    24.使用WSH获取文件信息 .............................................................................................................155 




----------------------- Page 6-----------------------


    25.FILESYSTEMOBJEC的方法和属性 ..................................................................................................156 


    26.对象FILE的属性 ........................................................................................................................160 


    27.文件夹对象属性 .......................................................................................................................161 


    28.驱动器对象属性 .......................................................................................................................161 


    29.使用WSH创建文本文件 .............................................................................................................162 


    30.使用WSH进行其它操作 .............................................................................................................164 


    31.运行其它应用程序 ...................................................................................................................164 


    32.创建快捷方式 ...........................................................................................................................165 


    33.接下来…… ...............................................................................................................................166 






                                                                    .....................................................................................167 


第九章 利用VBA控制其它应用程序..........................................................................................................................................................................116677 






    1.启动应用程序 .............................................................................................................................167 


    2.在应用程序之间切换 .................................................................................................................169 


    3.控制其它应用程序 .....................................................................................................................170 


    4.控制应用程序的其它方法 .........................................................................................................171 


    5.了解自动控制 .............................................................................................................................172 


    6.了解链接和嵌入 .........................................................................................................................172 


    7.使用VBA进行链接和嵌入 ...........................................................................................................173 


    8.COM和自动控制 ...........................................................................................................................174 


    9.了解绑定 .....................................................................................................................................174 


    10.后期绑定 ...................................................................................................................................174 


    11.早期绑定 ...................................................................................................................................174 


    12.建立到对象库的引用 ...............................................................................................................175 


    13.创建自动控制对象 ...................................................................................................................176 


    14.使用CREATEOBJECT函数 ...............................................................................................................176 


    15.使用自动控制创建一个新的WORD文档.....................................................................................177 


    16.使用GETOBJECT函数....................................................................................................................177 


    17.打开存在的WORD文档 ................................................................................................................178 


    18.使用关键字NEW..........................................................................................................................179 


    19.使用自动控制访问MICROSOFT                                       OUTLOOK .......................................................................................180 


    20.接下来…… ...............................................................................................................................181 






                                                   ..............................................................................................181 


第十章 对话框和自定义窗体............................................................................................................................................................................................118811 






    1.文件打开和另存为对话框 .........................................................................................................183 


    2.GETOPENFILENAME和GETSAVEASFILENAME方法 ...................................................................................187 


    3.创建窗体 .....................................................................................................................................188 


    4.创建用户窗体的工具 .................................................................................................................190 


    5.标签 .............................................................................................................................................191 


    6.文字框 .........................................................................................................................................191 


    7.框架 .............................................................................................................................................191 


    8.选项按钮 .....................................................................................................................................191 


    9.复选框 .........................................................................................................................................192 


    10.切换按钮 ...................................................................................................................................192 


    11.列表框 .......................................................................................................................................192 


    12.复合框 .......................................................................................................................................192 


    13.滚动条 .......................................................................................................................................192 


    14.旋转按钮 ...................................................................................................................................192 


    15.图像 ...........................................................................................................................................192 


    16.多页控件 ...................................................................................................................................192 


    17.TABSTRIP控件 .............................................................................................................................193 


    18.REFEDIT控件 ...............................................................................................................................193 


    19.在窗体上放置控件 ...................................................................................................................193 


    20.应用程序示例 1:信息调查 ....................................................................................................193 


    21.在窗体上添加按钮、选项框和其它控件 ...............................................................................194 




----------------------- Page 7-----------------------


    22.更改控件名称 ...........................................................................................................................197 


    23.设置其它控件属性 ...................................................................................................................197 


    24.准备工作表以储存窗体数据 ...................................................................................................198 


    25.显示自定义窗体 .......................................................................................................................199 


    26.设置TAB顺序 ..............................................................................................................................199 


    27.了解窗体和控件事件 ...............................................................................................................200 


    28.编写VBA过程对窗体和控件事件反应 .....................................................................................201 


    29.编写过程来初始化窗体 ...........................................................................................................201 


    30.编写过程填充列表框控件 .......................................................................................................203 


    31.编写过程控制选项按钮 ...........................................................................................................203 


    32.编写过程同步文字框和旋转按钮 ...........................................................................................204 


    33.编写过程关闭用户窗体 ...........................................................................................................204 


    34.转移窗体数据到工作表 ...........................................................................................................205 


    35.使用INFO SURVEY应用程序.........................................................................................................206 


    36.应用程序示例 2:学生和考试 ................................................................................................206 


    37.使用多页和TABSTRIP控件..........................................................................................................206 


    38.给窗体STUDENTS AND                       EXAMS自定义窗体编写VBA过程................................................................208 


    39.使用自定义窗体STUDENTS AND                                    EXAMS .........................................................................................212 


    40.接下来…… ...............................................................................................................................214 






                                                       ..........................................................................................214 


第十一章 自定义集合和类模块 ....................................................................................................................................................................................221144 






    1.使用集合 .....................................................................................................................................214 






    2.声明自定义集合 .........................................................................................................................215 


    3.给自定义集合添加对象 .............................................................................................................215 


    4.从自定义集合移出对象 .............................................................................................................216 


    5.创建自定义对象 .........................................................................................................................217 


    6.创建类 .........................................................................................................................................218 


    7.变量声明 .....................................................................................................................................218 


    8.定义类的属性 .............................................................................................................................218 


    9.创建PROPERTY  GET过程 .................................................................................................................219 


    10.创建PROPERTY  LET过程 ...............................................................................................................219 


    11.创建类方法 ...............................................................................................................................220 


    12.创建类的示例 ...........................................................................................................................220 


    13.类模块里的事件过程 ...............................................................................................................221 


    14.创建用户界面 ...........................................................................................................................221 


    15.观察VBA过程的执行 .................................................................................................................229 


    16.接下来…… ...............................................................................................................................231 






                                                                                  .......................................................................231 


第十二章 使用VBA创建自定义菜单和工具栏..............................................................................................................................................223311 






    1.工具栏 .........................................................................................................................................232 






    2.创建自定义工具栏 .....................................................................................................................233 


    3.删除自定义工具栏 .....................................................................................................................235 


    4.使用COMMANDBAR的属性 ................................................................................................................235 


    5.使用COMMANDBAR控件 ....................................................................................................................235 


    6.理解和使用控件属性 .................................................................................................................237 


    7.控件方法 .....................................................................................................................................239 


    8.使用菜单 .....................................................................................................................................240 


    9.菜单编程 .....................................................................................................................................241 


    10.创建子菜单 ...............................................................................................................................243 


    11.修改内置快捷菜单 ...................................................................................................................244 


    12.创建快捷菜单 ...........................................................................................................................247 


    13.接下来…… ...............................................................................................................................249 






                                                                 .....................................................................................249 


第十三章 调试VBA过程和处理错误..........................................................................................................................................................................224499 




----------------------- Page 8-----------------------


    1.测试VBA过程 ...............................................................................................................................249 


    2.终止过程 .....................................................................................................................................249 


    3.使用断点 .....................................................................................................................................250 


    4.在中断模式下使用立即窗口 .....................................................................................................253 


    5.使用STOP语句 ..............................................................................................................................254 


    6.添加监视表达式 .........................................................................................................................254 


    7.清除监视表达式 .........................................................................................................................256 


    8.使用快速监视 .............................................................................................................................256 


    9.使用本地窗口和调用堆栈对话框 .............................................................................................257 


    10.逐句运行VBA过程 .....................................................................................................................258 


    11.逐句运行过程 ...........................................................................................................................259 


    12.逐过程执行过程 .......................................................................................................................259 


    13.设置下一条语句 .......................................................................................................................260 


    14.显示下一条语句 .......................................................................................................................260 


    15.终止和重新设置VBA过程 .........................................................................................................260 


    16.了解和使用条件编译 ...............................................................................................................260 


    17.操纵书签 ...................................................................................................................................262 


    18.捕捉错误 ...................................................................................................................................262 


    17.接下来…… ...............................................................................................................................266 






                                                                              ...........................................................................266 


第十四章 微软EXCEL 2002 中的事件编程......................................................................................................................................................226666 






    1.事件过程介绍 .............................................................................................................................266 


    2.激活和失活事件 .........................................................................................................................267 


    3.事件次序 .....................................................................................................................................268 


    4.工作表事件 .................................................................................................................................268 


    5.工作簿事件 .................................................................................................................................272 


    6.图表事件 .....................................................................................................................................282 


    7.内嵌图表事件 .............................................................................................................................284 


    8.可为应用软件对象识别的事件 .................................................................................................285 


    9.查询表时间 .................................................................................................................................288 


    10.接下来…… ...............................................................................................................................289 






                                                         ........................................................................................289 


第十五章 在EXCEL里使用ACCESS ................................................................................................................................................................................228899 






    1.对象库 .........................................................................................................................................289 


    2.建立对对象库的引用 .................................................................................................................292 


    3.链接到ACCESS ...............................................................................................................................293 


    4.使用AUTOMATION链接到ACCESS数据库...........................................................................................293 


    5.使用DAO链接到ACCESS数据库 .....................................................................................................295 


    6.使用ADO链接到ACCESS数据库 .....................................................................................................295 


    7.从EXCEL执行ACCESS任务...............................................................................................................296 


    8.创建新ACCESS数据库 ...................................................................................................................296 


    9.打开ACCESS窗体 ...........................................................................................................................298 


    10.打开ACCESS报表 .........................................................................................................................300 


    11.运行ACCESS查询 .........................................................................................................................301 


    12.运行选择查询 ...........................................................................................................................302 


    13.运行参数查询 ...........................................................................................................................303 


    14.调用ACCESS函数 .........................................................................................................................304 


    15.获取ACCESS数据到EXCEL工作表.................................................................................................304 


    16.使用GETROWS方法获取数据 .......................................................................................................304 


    17.使用COPYFROMRECORDSET方法获取数据 .......................................................................................305 


    18.使用TRANSFERSPREADSHEET方法获取数据 ....................................................................................306 


    19.使用OPENDATABASE方法 ...............................................................................................................307 


    20.从ACCESS数据创建文本文件 .....................................................................................................309 


    21.从ACCESS数据创建查询表 .........................................................................................................310 




----------------------- Page 9-----------------------


22.在EXCEL里使用ACCESS数据.........................................................................................................311 


23.用ACCESS数据创建内嵌图表 .....................................................................................................311 


24.传输EXCEL电子表格到ACCESS数据库 .........................................................................................313 


25.将EXCEL电子表格链接到ACCESS数据库 .....................................................................................313 


26.将EXCEL电子表格导入ACCESS数据库 .........................................................................................314 


27.放置EXCEL数据到ACCESS表中.....................................................................................................314 


28.接下来…… ...............................................................................................................................316 




----------------------- Page 10-----------------------


VBA 语言基础                                                     橄榄树整理 






                             一、VBA 语言基础 






第一节 标识符 






一.定义 


    标识符是一种标识变量、常量、过程、函数、类等语言构成单位的符号,利用它可以完成 


对变量、常量、过程、函数、类等的引用。 


二.命名规则 


   1) 字母打头,由字母、数字和下划线组成,如 A987b_23Abc 


   2) 字符长度小于 40,(Excel2002 以上中文版等,可以用汉字且长度可达 254 个字符) 


   3) 不能与 VB 保留字重名,如 public, private, dim, goto, next, with, integer, single 


      等 






第二节 运算符 






   定义:运算符是代表 VB 某种运算功能的符号。 


   1)赋值运算符= 


   2)数学运算符&、+ (字符连接符)、+(加)、-(减)、Mod(取余)、\(整除)、*(乘)、/ 


   (除)、-(负号)、^(指数) 


   3)逻辑运算符 Not(非)、And(与)、Or(或)、Xor(异或)、Eqv(相等)、Imp(隐含) 


   4)关系运算符 = (相同)、<>(不等)、>(大于)、<(小于)、>=(不小于)、<=(不大 


   于)、 


   Like、Is 


   5)位运算符 Not(逻辑非)、And(逻辑与)、Or(逻辑或)、Xor(逻辑异或)、Eqv(逻辑 


   等)、Imp(隐含) 






第三节 数据类型 






    VBA 共有 12 种数据类型,具体见下表,此外用户还可以根据以下类型用 Type 自定义数据 


类型。 


     数据类型                类型标识符               字节 


     字符串型 String         $                   字符长度(0-65400) 


     字节型 Byte            无                   1 


     布尔型 Boolean         无                   2 


     整数型 Integer         %                   2 


     长整数型 Long           &                   4 


     单精度型 Single         !                   4 


     双精度型 Double         #                   8 


     日期型 Date            无                   8 公元 100/1/1-99/12/31 


     货币型 Currency        @                   8 


     小数点型 Decimal        无                   14 


     变体型 Variant         无                   以上任意类型,可变 


     对象型 Object          无                   4 






第四节 变量与常量 






1)VBA 允许使用未定义的变量,默认是变体变量。 


2)在模块通用说明部份,加入 Option Explicit 语句可以强迫用户进行变量定义。 


3)变量定义语句及变量作用域 


Dim    变量 as 类型 '定义为局部变量,如 Dim               xyz as integer 


Private 变量as 类型 '定义为私有变量,如 Private xyz as byte 


Public 变量as 类型 '定义为公有变量,如 Public xyz as single 


Global 变量as 类型 '定义为全局变量,如 Globlal xyz as date 


Static 变量 as 类型  '定义为静态变量,如 Static xyz as double 


一般变量作用域的原则是,那部份定义就在那部份起作用,模块中定义则在该模块那作用。 


4)常量为变量的一种特例,用 Const 定义,且定义时赋值,程序中不能改变值,作用域也如同 


                                   1 




----------------------- Page 11-----------------------


VBA 语言基础                                                      橄榄树整理 






变量作用域。如下定义:Const Pi=3.1415926as single 






第五节 数组 






    数组是包含相同数据类型的一组变量的集合,对数组中的单个变量引用通过数组索引下标 


进行。在内存中表现为一个连续的内存块,必须用 Global 或 Dim 语句来定义。定义规则如下: 


Dim 数组名([lower to ]upper [, [lower to ]upper, ….]) as type ;Lower 缺省值为 0。二 


维数组是按行列排列,如 XYZ(行,列)。 


    除了以上固定数组外,VBA 还有一种功能强大的动态数组,定义时无大小维数声明;在程 


序中再利用 Redim 语句来重新改变数组大小,原来数组内容可以通过加 preserve 关键字来保留。 


如下例: 


Dim array1() as double : Redim array1(5) : array1(3)=250 : Redim preserve array1(5,10) 






第六节 注释和赋值语句 






1)注释语句是用来说明程序中某些语句的功能和作用;VBA 中有两种方法标识为注释语句。 


   单引号 ’;如:’定义全局变量;可以位于别的语句之尾,也可单独一行 


   Rem ;如:Rem 定义全局变量;只能单独一行 


2)赋值语句是进行对变量或对象属性赋值的语句,采用赋值号                            =,如 X=123: 


Form1.caption=” 


我的窗口” 


对对象的赋值采用:set myobject=object 或 myobject:=object 






第七节 书写规范 






1)VBA 不区分标识符的字母大小写,一律认为是小写字母; 


2)一行可以书写多条语句,各语句之间以冒号 :                     分开; 


3)一条语句可以多行书写,以空格加下划线 _ 来标识下行为续行; 


4)标识符最好能简洁明了,不造成歧义。 






第八节 判断语句 






1)If…Then…Else 语句 


If conditionThen [statements][Else elsestatements] 


如 1:If A>B And C<D Then A=B+2 Else A=C+2 


如 2:If x>250Then x=x-100 


或者,可以使用块形式的语法: 


If condition Then 


[statements] 


[ElseIf condition-n Then 


[elseifstatements] ... 


[Else 


[elsestatements]] 


End If 


如 1: 


If Number < 10Then 


    Digits = 1 


ElseIf Number < 100Then 


    Digits = 2 


Else 


    Digits = 3 


End If 


2)Select Case…Case…End Case 语句 


如 1: 


Select Case Pid 


  Case “A101” 


  Price=200 


  Case “A102” 


  Price=300 






                                    2 




----------------------- Page 12-----------------------


VBA 语言基础                                                            橄榄树整理 






  …… 


  Case Else 


  Price=900 


End Case 


3)Choose 函数 


    choose(index, choce-1,choice-2,…,choice-n),可以用来选择自变量串列中的一个值, 


并将其返回,index 必要参数,数值表达式或字段,它的运算结果是一个数值,且界于 1 和可 


选择的项目数之间。choice 必要参数,Variant 表达式,包含可选择项目的其中之一。如: 






    GetChoice = Choose(Ind, "Speedy", "United", "Federal") 


4)Switch 函数 






    Switch(expr-1, value-1[, expr-2, value-2 _ [, expr-n,value-n]]) 


switch 函数和 Choose 函数类似,但它是以两个一组的方式返回所要的值,在串列中,最先为 


TRUE 的值会被返回。 expr 必要参数,要加以计算的 Variant 表达式。value 必要参数。如 


果相关的表达式为 True,则返回此部分的数值或表达式,没有一个表达式为 True,Switch 会 


返回一个 Null 值。 






第九节 循环语句 






1)For Next 语句 以指定次数来重复执行一组语句 


For counter = start To end [Step step]            ' step 缺省值为 1 


[statements] 


[Exit For] 


[statements] 


Next [counter] 


如 1: 


For Words = 10 To 1 Step -1            ' 建立 10 次循环 


    For Chars = 0 To 9                 ' 建立 10 次循环 


       MyString = MyString & Chars     ' 将数字添加到字符串中 


    Next Chars                         ' Increment counter 


    MyString = MyString & " "          ' 添加一个空格 


Next Words 


2)For Each…Next 语句 主要功能是对一个数组或集合对象进行,让所有元素重复执行一次 


语句 


For Each element In group 


Statements 


[Exit for] 


Statements 


Next [element] 


如 1: 


For Each rang2 In range1 


    With range2.interior 


          .colorindex=6 


          .pattern=xlSolid 


    End with 


Next 


    这上面一例中用到了 With…End With 语句,目的是省去对象多次调用,加快速度;语法 


为: 


With object 


[statements] 


End With 


3)Do…loop 语句 在条件为 true 时,重复执行区块命令 


Do {while |until} condition' while 为当型循环,until 为直到型循环,顾名思义,不多说 


啦 


Statements 


Exit do 


                                       3 




----------------------- Page 13-----------------------


VBA 语言基础                                                       橄榄树整理 






Statements 


Loop 


或者使用下面语法 


Do                       ' 先 do 再判断,即不论如何先干一次再说 


Statements 


Exit do 


Statements 


Loop {while |until} condition 






第十节 其他类语句和错误语句处理 






一.其他循环语句 


结构化程序使用以上判断和循环语句已经足够,建议不要轻易使用下面的语句,虽然 VBA 还支 


持。 


1) Goto line 该语句为跳转到 line 语句行 


2) On expression gosub destinatioinlist 或者 on expression goto destinationlist 语 


   句为根据 exprssion 表达式值来跳转到所要的行号或行标记 


3) Gosub line…line…Return 语句,         Return 返回到 Gosub line 行,如下例: 


Sub gosubtry() 


    Dim num 


    Num=inputbox(“输入一个数字,此值将会被判断循环”) 


    If num>0 then Gosub Routine1 :Debug.print num:Exit sub 


    Routine1: 


    Num=num/5 


    Return 


End sub 


4) while…wend 语句,只要条件为 TRUE,循环就执行,这是以前 VB 老语法保留下来的,如下 


   例: 


while condition‘while I<50 


[statements]  ‘I=I+1 


wend          ‘Wend 


二.错误语句处理 


执行阶段有时会有错误的情况发生,利用 On Error 语句来处理错误,启动一个错误的处理程序。 


语法如下: 


On Error Goto Line ‘当错误发生时,会立刻转移到 line 行去 


On Error Resume Next‘当错误发生时,会立刻转移到发生错误的下一行去 


On Erro Goto 0     ‘当错误发生时,会立刻停止过程中任何错误处理过程 






第十一节 过程和函数 






    过程是构成程序的一个模块,往往用来完成一个相对独立的功能。过程可以使程序更清晰、 


更具结构性。VBA 具有四种过程:Sub 过程、Function 函数、Property 属性过程和 Event 事件 


过程。 


一.Sub 过程 


    Sub 过程的参数有两种传递方式:按值传递(ByVal)和按地址传递(ByRef)。如下例: 


    Sub password (ByVal x as integer,  ByRef y as integer) 


       If y=100 then y=x+y else y=x-y 


       x=x+100 


    End sub 


    Sub call_password () 


       Dim x1 as integer 


       Dim y1 as integer 


       x1=12 


       y1=100 


       Call password (x1,y1) ‘调用过程方式:1. Call 过程名(参数 1, 参数 2…) ; 2. 过 


       程名 参数 1, 参数 2… 






                                    4 




----------------------- Page 14-----------------------


VBA 语言基础                                                      橄榄树整理 






       debug.print x1,y1 ‘结果是 12、112,y1 按地址传递改变了值,而 x1 按值传递,未 


    改变原值 


    End sub 


二.Function 函数 


    函数实际是实现一种映射,它通过一定的映射规则,完成运算并返回结果。参数传递也两 


种:按值传递(ByVal)和按地址传递(ByRef)。如下例: 






    Function password(ByVal x as integer, byref y as integer) as boolean 


       If y=100 then y=x+y else y=x-y 


       x=x+100 


       if y=150 then password=true else password=false 






    End Function 


    Sub call_password () 


       Dim x1 as integer 


       Dim y1 as integer 


       x1=12 


       y1=100 


       if password then‘调用函数:1. 作为一个表达式放在=右端 ; 2. 作为参数使用 


       debug.print x1 


       end if 


    End sub 


三.Property 属性过程和 Event 事件过程 


    这是 VB 在对象功能上添加的两个过程,与对象特征密切相关,也是 VBA 比较重要组成,技 


术比较复杂,可以参考相关书籍。 






第十二节内部函数 






    在 VBA 程序语言中有许多内置函数,可以帮助程序代码设计和减少代码的编写工作。 


一.测试函数 


IsNumeric(x)      ‘是否为数字, 返回 Boolean 结果,True or False 


IsDate(x)         ‘是否是日期, 返回 Boolean 结果,True or False 


IsEmpty(x)        ‘是否为 Empty, 返回 Boolean 结果,True or False 


IsArray(x)        ‘指出变量是否为一个数组。 


IsError(expression) ‘指出表达式是否为一个错误值 


IsNull(expression) ‘指出表达式是否不包含任何有效数据 (Null)。 


IsObject(identifier)‘指出标识符是否表示对象变量 


二.数学函数 


Sin(X)、Cos(X)、Tan(X)、Atan(x) 三角函数,单位为弧度 


Log(x) 返回 x 的自然对数 


Exp(x)返回 ex 






Abs(x) 返回绝对值 


Int(number)、Fix(number) 都返回参数的整数部分,区别:Int 将 -8.4 转换成 -9,而 Fix 将 


-8.4 转换成 -8 


Sgn(number) 返回一个 Variant (Integer),指出参数的正负号 


Sqr(number) 返回一个 Double,指定参数的平方根 


VarType(varname) 返回一个 Integer,指出变量的子类型 


Rnd(x)返回 0-1 之间的单精度数据,x 为随机种子 


三.字符串函数 


Trim(string)         去掉 string 左右两端空白 


Ltrim(string)        去掉 string 左端空白 


Rtrim(string)        去掉 string 右端空白 


Len(string)          计算 string 长度 


Left(string, x)      取 string 左段 x 个字符组成的字符串 


Right(string, x)     取 string 右段 x 个字符组成的字符串 


Mid(string, start,x) 取 string 从 start 位开始的 x 个字符组成的字符串 


Ucase(string)        转换为大写 


                                    5 




----------------------- Page 15-----------------------


VBA 语言基础                                                       橄榄树整理 






Lcase(string)        转换为小写 


Space(x)             返回 x 个空白的字符串 


Asc(string)          返回一个 integer,代表字符串中首字母的字符代码 


Chr(charcode)        返回 string,其中包含有与指定的字符代码相关的字符 


四.转换函数 


CBool(expression)    转换为 Boolean 型 


CByte(expression)    转换为 Byte 型 


CCur(expression)     转换为 Currency 型 


CDate(expression)    转换为 Date 型 


CDbl(expression)     转换为 Double 型 


CDec(expression)     转换为 Decemal 型 


CInt(expression)     转换为 Integer 型 


CLng(expression)     转换为 Long 型 


CSng(expression)     转换为 Single 型 


CStr(expression)     转换为 String 型 


CVar(expression)     转换为 Variant 型 


Val(string)          转换为数据型 


Str(number)          转换为 String 


五.时间函数 


Now        返回一个 Variant (Date),根据计算机系统设置的日期和时间来指定日期和时 


间。 


Date       返回包含系统日期的 Variant (Date)。 


Time       返回一个指明当前系统时间的 Variant (Date)。 


Timer      返回一个 Single,代表从午夜开始到现在经过的秒数。 


TimeSerial(hour, minute, second) 返回一个 Variant (Date),包含具有具体时、分、秒的 


时间。 


DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]]) 返回 Variant 


(Long) 的值,表示两个指定日期间的时间间隔数目 


Second(time) 返回一个 Variant (Integer),其值为 0 到 59 之间的整数,表示一分钟之中 


的某个秒 


Minute(time) 返回一个 Variant (Integer),其值为 0 到 59 之间的整数,表示一小时中的 


某分钟 


Hour(time) 返回一个 Variant (Integer),其值为 0 到 23 之间的整数,表示一天之中的某 


一钟点 


Day(date) 返回一个 Variant (Integer),其值为 1 到 31 之间的整数,表示一个月中的某 


一日 


Month(date) 返回一个 Variant (Integer),其值为 1 到 12 之间的整数,表示一年中的某月 


Year(date) 返回 Variant (Integer),包含表示年份的整数。 


Weekday(date, [firstdayofweek]) 返回一个 Variant (Integer),包含一个整数,代表某个 


日期是星期几 






第十三节 文件操作 






文件 


Dir[(pathname[, attributes])] ;pathname 可选参数,用来指定文件名的字符串表达式,可 


能包含目录或文件夹、以及驱动器。如果没有找到 pathname,则会返回零长度字符串 (""); 


attributes 可选参数。常数或数值表达式,其总和用来指定文件属性。如果省略,则会返回匹 


配 pathname 但不包含属性的文件。 


删除 


Kill pathname 从磁盘中删除文件, pathname 参数是用来指定一个文件名 


RmDir pathname 从磁盘中删除目录,pathname 参数是用来指定一个文件夹 


打开 


Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength] 能够 


对文件输入/输出 (I/O)。 


pathname 必要。字符串表达式,指定文件名,该文件名可能还包括目录、文件夹及驱动器。 


                                    6 




----------------------- Page 16-----------------------


VBA 语言基础                                                     橄榄树整理 






mode 必要。关键字,指定文件方式,有 Append、Binary、Input、Output、或 Random 方式。 


如果未指定方式,则以 Random 访问方式打开文件。 


access 可选。关键字,说明打开的文件可以进行的操作,有 Read、Write、或 Read Write 操 


作。 


lock 可选。关键字,说明限定于其它进程打开的文件的操作,有 Shared、Lock Read、Lock 


Write、 


和 Lock Read Write 操作。 


filenumber 必要。一个有效的文件号,范围在 1 到 511 之间。使用 FreeFile 函数可得到下 


一个可用的文件号。 reclength 可选。小于或等于 32,767(字节)的一个数。对于用随机访 


问方式打开的文件,该值就是记录长度。对于顺序文件,该值就是缓冲字符数。 


说明 对文件做任何 I/O 操作之前都必须先打开文件。Open 语句分配一个缓冲区供文件进行 


I/O 之用,并决定缓冲区所使用的访问方式。如果 pathname 指定的文件不存在,那么,在用 


Append、Binary、Output、或 Random 方式打开文件时,可以建立这一文件。如果文件已由其 


它进程打开,而且不允许指定的访问类型,则 Open 操作失败,而且会有错误发生。如果 mode 


是 Binary 方式,则 Len 子句会被忽略掉。 


重要 在 Binary、Input 和 Random 方式下可以用不同的文件号打开同一文件,而不必先将该 


文件关闭。在 Append 和 Output 方式下,如果要用不同的文件号打开同一文件,则必须在打 


开文件之前先关闭该文件。 


读入 


Input #filenumber, varlist 从已打开的顺序文件中读出数据并将数据指定给变量 


Get [#]filenumber, [recnumber], varname 将一个已打开的磁盘文件读入一个变量之中。 


写入 


Write #filenumber, [outputlist] 将数据写入顺序文件 


Print #filenumber, [outputlist] 将格式化显示的数据写入顺序文件中 


Put [#]filenumber, [recnumber], varname 将一个变量的数据写入磁盘文件中。 


关闭 


Close [filenumberlist] 关闭 Open 语句所打开的输入/输出 (I/O) 文件 


注意 如果今后想用 Input # 语句读出文件的数据,就要用 Write # 语句而不用 Print # 语 


句将数据写入文件。因为在使用 Write # 时,将数据域分界就可确保每个数据域的完整性,因 


此可用 Input # 再将数据读出来。使用 Write # 还能确保任何地区的数据都被正确读出。Write 


与 Print # 语句不同,当要将数据写入文件时,Write # 语句会在项目和用来标记字符串的引 


号之间插入逗号。Write # 语句在将 outputlist 中的最后一个字符写入文件后会插入一个新 


行字符,即回车换行符,(Chr(13) + Chr(10))。 


其他文件函数 


LOF(filenumber) 返回一个 Long,表示用 Open 语句打开的文件的大小,该大小以字节为单 


位。 


EOF(filenumber) 返回一个 Integer,它包含 Boolean 值 True,表明已经到达为 Random 或 


顺序 Input 打开的文件的结尾。 


Loc(filenumber) 返回一个 Long,在已打开的文件中指定当前读/写位置 


Seek(filenumber) 返回一个 Long,在 Open 语句打开的文件中指定当前的读/写位 






                                    7 




----------------------- Page 17-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                      理 






                      二、Visual BASIC 程序设计网络教学 






                             第一课 VBA 是什么 






1.1 VBA 是什么 






    直到 90 年代早期,使应用程序自动化还是充满挑战性的领域.对每个需要自动化的应用程 


序,人们不得不学习一种不同的自动化语言.例如:可以用 EXCEL 的宏语言来使 EXCEL 自动化,使 


用 WORD BASIC 使 WORD 自动化,等等.微软决定让它开发出来的应用程序共享一种通用的自动化 


语言--------Visual Basic For Application(VBA),可以认为 VBA 是非常流行的应用程序开发 


语言 VASUAL BASIC 的子集.实际上 VBA 是"寄生于"VB 应用程序的版本.VBA 和 VB 的区别包括如 


下几个方面: 


    1. VB 是设计用于创建标准的应用程序,而 VBA 是使已有的应用程序(EXCEL 等)自动化 


    2. VB 具有自己的开发环境,而 VBA 必须寄生于已有的应用程序. 


   3. 要运行 VB 开发的应用程序,用户不必安装 VB,因为 VB 开发出的应用程序是可执行文件 


(*.EXE),而 VBA 开发的程序必须依赖于它的"父"应用程序,例如 EXCEL. 


   尽管存在这些不同,VBA 和 VB 在结构上仍然十分相似.事实上,如果你已经了解了 VB,会发现 


学习 VBA 非常快.相应的,学完 VBA 会给学习 VB 打下坚实的基础.而且,当学会在 EXCEL 中用 VBA 


创建解决方案后,即已具备在 WORD ACCESS OUTLOOK FOXPRO PROWERPOINT 中用 VBA 创建解决方 


案的大部分知识. 


    * VBA 一个关键特征是你所学的知识在微软的一些产品中可以相互转化. 


    * VBA 可以称作 EXCEL 的"遥控器". 


   VBA 究竟是什么?更确切地讲,它是一种自动化语言,它可以使常用的程序自动化,可以创建 


自定义的解决方案. 


     此外,如果你愿意,还可以将 EXCEL 用做开发平台实现应用程序. 






1.2 EXCEL 环境中基于应用程序自动化的优点 






    也许你想知道 VBA 可以干什么?使用 VBA 可以实现的功能包括: 


    1. 使重复的任务自动化. 


    2. 自定义 EXCEL 工具栏,菜单和界面. 


    3. 简化模板的使用. 


    4. 自定义 EXCEL,使其成为开发平台. 


    5. 创建报表. 


    6. 对数据进行复杂的操作和分析. 


    用 EXCEL 作为开发平台有如下原因: 


    1. EXCEL 本身功能强大,包括打印,文件处理,格式化和文本编辑. 


    2. EXCEL 内置大量函数. 


    3. EXCEL 界面熟悉. 


    4. 可连接到多种数据库. 


    用其他语言开发应用程序,一半的工作是编写一些基本功能的模块,包括文件的打开和保存, 


打印,复制等.而用 EXCEL 作为开发平台,则由于 EXCEL 已经具备这些基本功能,你要做的只是使 


用它. 






    1.3 录制简单的宏 






    在介绍学习 VBA 之前,应该花几分钟录制一个宏。 


    新术语:"宏",指一系列 EXCEL 能够执行的 VBA 语句。 


    以下将要录制的宏非常简单,只是改变单元格颜色。请完成如下步骤: 


    1)打开新工作簿,确认其他工作簿已经关闭。 


    2)选择 A1 单元格。调出"常用"工具栏。 


    3)选择"工具"-"宏"-"录制新宏"。 


    4)输入"改变颜色"作为宏名替换默认宏名,单击确定,注意,此时状态栏中显示"录制",特 


别是"停止录制"工具栏也显示出来。替换默认宏名主要是便于分别这些宏。 


    ★ 宏名最多可为 255 个字符,并且必须以字母开始。其中可用的字符包括:字母、数字和 






                                    1 




----------------------- Page 18-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                      理 


下划线。宏名中不允许出现空格。通常用下划线代表空格。 


    5)选择"格式"的"单元格",选择"图案"选项中的红色,单击"确定"。 


    6)单击"停止录制"工具栏按钮,结束宏录制过程。 


    ※ 如果"停止录制"工具栏开始并未出现,请选择"工具"-"宏"-"停止录制"。 


    录制完一个宏后就可以执行它了。 






    1.4 执行宏 






    当执行一个宏时,EXCEL 按照宏语句执行的情况就像 VBA 代码在对 EXCEL 进行"遥控"。但 


VBA 的"遥控"不仅能使操作变得简便,还能使你获得一些使用 EXCEL 标准命令所无法实现的功 


能。而且,一旦熟悉了 EXCEL 的"遥控",你都会奇怪自己在没有这些"遥控"的情况下,到底是 


怎么熬过来的。要执行刚才录制的宏,可以按以下步骤进行: 


    1)选择任何一个单元格,比如 A3。 


    2)选择"工具"-"宏"-"宏",显示"宏"对话框。 


   3)选择"改变颜色",选择"执行",则 A3 单元格的颜色变为红色。试着选择其它单元格和 


几个单元格组成的区域,然后再执行宏,以便加深印象。 






    1.5 查看录制的代码 






    到底是什么在控制 EXCEL 的运行呢?你可能有些疑惑.好,让我们看看 VBA 的语句吧. 


    1)选择"工具"-"宏"-"宏",显示"宏"对话框。 


    2)单击列表中的"改变颜色",选择"编辑"按钮。 


   此时,会打开 VBA 的编辑器窗口(VBE)。关于该编辑器,以后再详细说明,先将注意力集 


中到显示的代码上。代码如下:(日期和姓名会有不同) 


Sub 改变颜色() 





' 改变颜色 Macro 


' xw 记录的宏 2000-6-10 








With Selection.Interior 


.ColorIndex = 3 


.Pattern = xlSolid 


.PatternColorIndex = xlAutomatic 


End With 


End Sub 


将来会十分熟悉这种代码,虽然现在它们看上去像一种奇怪的外语。学习 VBA 或编程语言在某 


种程度上比较像在学习一种外语。 


Sub 改变颜色():这是宏的名称。 


中间的以" '"开头的五行称为"注释",它在录制宏时自动产生。 


以 With 开头到 End With 结束的结构是 With 结构语句,这段语句是宏的主要部分。注意单词 


"selection",它代表"突出显示的区域"(即:选定区域)。With Selection.Interior :它读 


作"选择区域的的内部".这整段语句设置该区域内部的一些"属性"。 


其中: 


.ColorIndex = 3: 将该内部设为红色。注意:有一小圆点,它的作用在于简化语句,小圆点代 


替出现在 With 后的词,它是 With 结构的一部分。另外:红色被数字化为 3.(红色警戒是否可称 


作:3 号警戒,嗯?)有兴趣的话,你将 3 改为其他数字试试看。 


.Pattern = xlSolid:设置该区域的内部图案。由于是录制宏,所以,虽然你并未设置这一项, 


宏仍然将其记录下来(因为在"图案"选项中有此一项,只是你未曾设置而已)。xlSolid 表示纯 


色。 


.PatternColorIndex = xlAutomatic:表示内部图案底纹颜色为自动配色。 


End With:结束 With 语句。 


End Sub:整个宏的结束语 






                                    2 




----------------------- Page 19-----------------------


VisualBASIC 程序设计网络教学                                              橄榄树 


整                                                                     理 


    1.6 编辑录制的代码 






     在上一节,我们录制了一个宏并查看了代码,代码中有两句实际上并不起作用。哪两句? 


现在,在宏中作一个修改,删除多余行,直到和下面代码相同: 


Sub 改变颜色() 





' 改变颜色 Macro 


' xw 记录的宏 2000-6-10 








With Selection.Interior 


.ColorIndex = 3 


End With 


End Sub 


   完成后,在工作表中试验一下。你会发现结果和修改前的状况一样。在 With 语句前加入 


一行: 


Range("A5").Select 


    试着运行该宏,则无论开始选择哪个单元格,宏运行结果都是使 A5 单元格变红. 


    现在可以看到,编辑录制的宏同样非常简单。需要编辑宏是因为以下三个方面的原因。一: 


在录制中出错而不得不修改。二:录制的宏中有多余的语句需要删除,提高宏的运行速度。三: 


希望增加宏的功能。比如:加入判断或循环等无法录制的语句。 






    1.7 录制宏的局限性 






    希望自动化的许多 EXCEL 过程大多都可以用录制宏来完成.但是宏记录器存在以下局限性. 


通过宏记录器无法完成的工作有: 


    1)录制的宏无判断或循环能力. 


    2)人机交互能力差,即用户无法进行输入,计算机无法给出提示. 


    3)无法显示 EXCEL 对话框. 


    4)无法显示自定义窗体. 






    1.8 小结 






    本课中,你已经掌握了 VBA 的一些基础知识,你会录制宏、编辑宏而且了解了录制宏的局限 


性.你很努力.并且已经为将来学习 VBA 甚至 VB 等编程语言打下了基础.关键是你已经了解了一 


个谜底,就是说,你了解了什么是编程.下面是些小练习,做完后才可以去玩哟. 


    思考: 


    1)VBA 只能用于 EXCEL 吗? 


    2)VBA 是基于哪种语言? 


    3)说说 EXCEL 和 VBA 的关系. 


    4)为什么要用宏? 






                            第二课 处理录制的宏 






    2.1 为宏指定快捷键 






    你也许希望为经常使用的宏指定快捷键。快捷键是指键的组合,当其按下时执行一条命令。 


例如:CTRL+C 


    在许多程序中代表"复制"命令。当给宏指定了快捷键后,就可以用快捷键来执行宏,而不 


必通过"工具"菜单。 


    注意:当包含宏的工作簿打开时间,为宏指定快捷键会覆盖 EXCEL 默认的快捷键。例如: 


把 CTRL+C 指定给某个宏,那么 CTRL+C 就不再执行复制命令。用以下方法可以打印出 EXCEL 的 


快捷键清单(用 A4 纸打印共有 24 页之多): 


    1)打开 EXCEL 帮助文件并选择"目录"选项。 


    2)从"使用快捷键"文件夹中选择""快捷键"标题。 


    3)右击该标题,从快捷菜单中选择"打印"。 


    4)选择"打印所选标题和所有子主题",单击"确定"。 






                                    3 




----------------------- Page 20-----------------------


VisualBASIC 程序设计网络教学                                            橄榄树 


整                                                                   理 


可以在创建宏时指定快捷键,也可以在创建后再指定。要在创建(录制)宏时指定快捷键,只 


须在录制宏时在输入宏名后,在"快捷键"文本框中输入相应的键。录制宏后指定快捷键也很简 


单,只需选择"工具""宏",显示"宏"对话框,选择要指定快捷键的宏,再单击"选项"按钮,通 


过"选项"对话框进行设置。 






    2.2 决定宏保存的位置 






    宏可保存在三种可能的位置: 


    1)当前工作簿。(只有该工作簿打开时,该宏才可用。) 


    2)新工作簿。 


    3)个人宏工作簿。 






    2.3 个人宏工作簿 






   个人宏工作簿,是为宏而设计的一种特殊的具有自动隐藏特性的工作簿。第一次将宏创建 






到个人宏工作簿时,会创建名为"PERSONAL.XLS"的新文件。如果该文件存在,则每当 EXCEL 启 


动时会自动将此文件打开并隐藏在活动工作簿后面(在"窗口"菜单中选择"取消隐藏"后,可以 


很方便地发现它的存在。)如果你要让某个宏在多个工作簿都能使用,那么就应当创建个人宏工 


作 簿 , 并 将 宏 保 存 于 其 中 。 个 人 宏 工 作 簿 保 存 在 "XLSTART" 文 件 夹 中 。 具 体 路 


径 为 : 


C:\WINDOWS\Profiles\Application Data\Microsoft\Excel\XLSTART。可以以单词"XLSTART" 


查询。 


   注意:如果存在个人宏工作簿,则每当 EXCEL 启动时会自动将此文件打开并隐藏。因为它 


存放在 XLSTART 文件夹内。 


    2.3.1 保存宏到个人宏工作簿 


    本练习,将保存一个简单的宏到个人宏工作簿,该宏为文本加下划线并改为斜体,步骤如下: 


    1)建立一个名为"HOUR2"的工作簿,选择"工具"-"宏"-"录制新宏",显示"录制新宏"对话框. 


    2)输入"格式化文本"作为宏名. 


    3)从"保存在"下拉框中选择"个人宏工作簿". 


    4)单击"确定"按钮.现在进入录制模式. 


    5)单击"斜体"工具栏按钮.一段时间内,鼠标出现沙漏,特别是在第一次创建个人宏工作簿 


时,因为 EXCEL 在创建该工作簿. 


    6)单击"下划线"按钮. 


    7)停止录制. 


    2.3.2 使用并编辑个人宏工作簿中的宏 


    刚才已经保存了一个宏到个人宏工作簿,现在可以在任何工作簿中使用该宏.可按如下步骤 


操作: 


    1)关闭所有 EXCEL 工作簿. 


    2)任意打开一个 EXCEL 文件.(EXCEL 自动将个人宏工作簿同时打开并隐藏.) 


    3)在 A3 中输入你的名字. 


    4)选择"工具"-"宏",显示宏对话框.现在可以在宏列表中看到"格式化文本"这个宏. 


    5)选择"格式化文本"宏,并执行.现在 A3 单元格中,你的名字变为斜体字还带有下划线.选 


择"窗口"-"取消隐藏",可以将 PERSONAL.XLS 显示出来,其中没有任何文字,但通过 VBA 编辑器可 


以在其中的模块中找到"格式化文本"这个宏.在 VBA 编辑器中可以对该宏进行直接编辑或者删 


除.如果 PERSONAL.XLS 中一个宏都没有,在启动 EXCEL 时仍会打开 PERSONAL.XLS,这也许是 


EXCEL 存在的一个小毛病. 






    2.4 将宏指定给按钮 






    即使通过快捷键可以是宏的执行变快,但是一旦宏的数量多了也难于记忆,而且,如果宏是 


由其他人来使用,难道你要他们也记住那么多的快捷键吗? 


    作为 EXCEL 开发者,一个主要的目标是为自动化提供一个易于操作的界面."按钮"是最常见 


的界面组成元素之一.通过使用"窗体"工具栏,可以为工作簿中的工作表添加按钮。在创建完一 


个按钮后,可以为它指定宏,然后你的用户就可以通过单击按钮来执行宏。在本练习中,将创 


建一个按钮,并为它指定一个宏,然后用该按钮来执行宏。具体步骤如下: 


    1)打开"HOUR2"工作簿。 


    2)调出"窗体"工具栏。 






                                   4 




----------------------- Page 21-----------------------


VisualBASIC 程序设计网络教学                                            橄榄树 


整                                                                   理 


    3)单击"窗体"工具栏中的"按钮"控件,此时鼠标变成十字形状。 


    4)在希望放置按钮的位置按下鼠标左键,拖动鼠标画出一个矩形,这个矩形代表了该按钮 


的大小。对大小满意后放开鼠标左键,这样一个命令按钮就添加到了工作表中,同时 EXCEL 自 


动显示"指定宏"对话框。 


    5)从"指定宏"对话框中选择"格式化文本",单击"确定"。这样,就把该宏指定给命令按钮。 


    6)在按钮的标题"按钮 1"前单击鼠标左键,按下 DELETE 直到删除所有文本,输入"格式化 


"作为标题。 


    7)单击按钮外的任意位置,现在该按钮的标题由默认的"按钮 1"变为"格式化"而且被指定 


了一个宏。 


    8)试着在某个单元格中输入文本,单击按钮运行该宏。 


    当鼠标移动至该按钮时自动变成手的形状,如果要改变其大小或标题,只需用右键单击该 


按钮就可以进行修改和设置。很明显,你再也不需记住宏的名字或快捷键了,只需按一下按钮。 






    2.5 将宏指定给图片或其他对象 






    要执行宏有多种方法可以选择,可以将宏指定给按钮等控件,还可以指定给图片、自定义 


工具栏、窗体甚至可以将宏指定给某个"事件",比如单击工作表,双击工作表,激活工作表, 


打开工作簿等等,"事件"是一个重要的概念,除此而外"方法""对象"都是将来你会经常接触到 


的。现在它们看来十分抽象,但是将来你会很熟悉这些词语。指定宏到图片十分简单,只需单 


击某个图片,单击快捷菜单中的"指定宏"进行设置即可。 


    如果不希望在工作表上添加控件或图片执行宏,还有一种方法可以选择:将宏指定给"工具 


栏按钮",可按如下步骤进行: 


    1)打开"HOUR2"工作簿,选择"工具"-"定义",显示"自定义工具栏"对话框。 


    2)从"类别"列表框中选择"宏",从"命令"列表框中选择"自定义按钮"。 


    3)将"自定义按钮"拖动到工具栏。 


    4)右键单击该按钮,选择"指定宏",显示"指定宏"对话框。 


    5)选择"格式化文本"并确定。 


    6)单击"关闭"按钮,关闭"自定义工具栏"对话框。 


    7)试着在某个单元格中输入文本,单击工具栏按钮运行该宏。 






    2.6 小结 






   小结与思考: 宏存放于三个可能的位置。个人宏工作簿存放的位置和特性。执行宏的方式。 


指定宏是为某个对象的事件指定一个程序,一旦这个对象以该事件激活,系统将运行指定的程 


序。 


    常用的对象有:workbook,worksheet,range,cells,图表,图片,数据透视表,控件,窗体,工 


具栏.每一个对象都有其可以响应的特殊事件(也有一些通用事件如单击或双击等)。如有兴趣, 


可以通过 EXCEL 帮助文件查询这几个词条。在 EXCEL 中看到的几乎都是属于某个对象,而在 EXCEL 


中所做的许多工作,如移动一下鼠标等等,都可能触发了一个事件。下一学时我们将共同学习" 


控件"。 






                            第三课 学习控件 






    3.1 EXCEL 开发过程简介 






    需要对以下问题有个大致的概念. 


    1)谁使用-----这决定了程序的操作难度及界面感观. 


    2)数据来源和保存在哪里-----这决定了程序的结构. 


    3)如何操作-----这将决定程序的界面和细节. 


    4)数据处理的结果-----最终决定程序的价值. 






    3.2 认识不同的控件 






    开始时请关闭所有工作簿,打开一个新工作簿并另存为"HOUR3".在工具栏上单击鼠标右键, 


从快捷菜单中选择"窗体",显示"窗体"工具栏.其中有 16 个控件,只有 9 个可放到工作表内。 


    1)标签:它用于表现静态文本。 


    2)分组框:它用于将其他控件进行组合。 


    3)按钮:用于执行宏命令。 






                                  5 




----------------------- Page 22-----------------------


VisualBASIC 程序设计网络教学                                              橄榄树 


整                                                                     理 


   4)复选框:它是一个选择控件,通过单击可以选择和取消选择,可以多项选择。 


    5)选项按钮:通常几个选项按钮组合在一起使用,在一组中只能选择一个选项按钮。 


    6)列表框:用于显示多个选项并从中选择。只能单选。 


    7)组合框:用于显示多个选项并从中选择。可以选择其中的项目或者输入一个其它值。 


    8)滚动条:不是你常见的来给很长的窗体添加滚动能力的控件,而是一种选择机制。例如 


调节过渡色的滚动条控件。包括水平滚动条和垂直滚动条。 


    9)微调控件:也是一种数值选择机制,通过单击控件的箭头来选择数值。例如改变 Windows 


日期或时间就会使用到微调控件。 






    3.3 向工作表添加控件 






    用 EXCEL 设计界面十分简单,要将控件添加到工作表上,可以按以下步骤操作: 


    1)创建新工作簿并另存为"HOUR3",显示"窗体"工具栏. 


    2)选择"标签"控件. 


    3)将鼠标定位到 E1,此时鼠标变成小十字. 


    4)按下左键,拖动大约四个单元格长度,放开鼠标左键.如果希望控件大小易于控制,可在创 


建该控件时按下 ALT 拖动. 


    5)在标签 1 上单击右键,选择"编辑文字",现在可以输入文字.完成后,单击任何单元格退出 


文字编辑. 


    6)通过以上步骤可以添加其它控件到工作表中,不再赘述. 






    3.4 设置控件的特性 






    设置控件的特性,可以按以下步骤操作: 


    1)选中先前创建的复选框控件,如果没有马上创建一个. 


    2)右击该控件,选择"控制"选项卡. 


    3)在"单元格链接"中输入 A1 并确定. 


    4)单击任意单元格,退出设置. 


    5)用鼠标左键单击复选框,A1 出现 TRUE,这意味着该控件被选中.再次单击该控件,A1 出现 


FALSE. 


    6)选择刚才创建的滚动条控件.并调出"设置控件格式"对话框. 


    7)在"单元格链接"中输入 A3 并确定. 


    8)在滚动条外任意单元格单击鼠标左键,使滚动条不被选择. 


    9)用鼠标单击滚动条上的箭头,则 A1 的数值增加 1,继续单击则 A1 的数值继续增加. 


    10)保存并关闭该工作簿. 






    3.5 给控件命名 






    当创建一个控件时 EXCEL 会自动给它指定一个名字,但不便于理解和记忆,为控件取名的方 


法基本和给单元格或区域取名的方法相同.选中某个控件,再在位于公式栏上的"名字"编辑框输 


入控件名字.这样就给控件更改了名字. 






    3.6 使用用户窗体 






    如果希望创建专业级的应用程序,并且方便用户输入数据,那么应该使用用户窗体.用户窗 


体可以作为程序的对话框和窗口.向用户窗体添加控件基本类似于向工作表添加控件,然而第一 


步要创建一个用户窗体.这可以通过 VBA 编辑器实现.具体按以下步骤操作: 


    1)打开"HOUR3"工作簿,选择"工具"-"宏"-"VBA 编辑器",打开 VBA 编辑器. 


    2)在 VBA 编辑器中选择工具栏上的"插入用户窗体"按钮或者选择"插入"菜单,从下拉菜单 


中选择"用户窗体" 


    现在,VBA 编辑器中出现一个名为"USERFORM1"的窗体,"控件工具箱"同时出现,在其中有许 


多已经熟悉的控件,另外还有一些新的控件. 


    这些新的控件是: 


    A)切换按钮:该控件如果被选中,那么会保持被按下的状态.如果再次单击它就恢复为没有 


按下的状态.EXCEL 工具栏中有几个这样的按钮,例如:"全屏显示","加粗","下划线"以及"窗体" 


工具栏中的"切换网格"等. 


    B)选项卡条(TabStrip):它是包含多个选项卡的控件.通常用来对相关的信息进行组织或分 






                                   6 




----------------------- Page 23-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                      理 


类.例如:你也许希望用选项卡条来显示各个地区的销售信息,可以给每个地区设置一个选项卡. 


在默认时,选项卡包含两页,分别叫做 TAB1 和 TAB2,可以添加更多的选项卡. 


   C)多页:外观类似选项卡条,是包含一页或多页的控件.选项卡条给人相似的外观,而多页控 


件的各页包含各自不同的控件,有各自不同的布局.多页的例子很多,例如:"设置控件格式"对话 


框和"工具"菜单中的"选项"对话框.以及"格式"菜单中的"单元格..."对话框. 


      D) 图 像 控 件 : 它 允 许 向 窗 体 上 放 置 图 片 . 图 片 格 式 须 


为 :*.bmp,*.cur,*.gif,*.ico,*.jpg,*.wmf. 


   F)RefEdit:这是工具箱中默认情况下的最后一个控件。它外观象文本框,通过这个控件可 


以将用户窗体折叠起来,以便选择单元格区域。还记得在使用 fx"粘贴函数"时的情况吗? 


    通过实践,我们会逐渐掌握每个控件的特性,这的确需要花时间,但不必死记硬背。 


   在对用户窗体设计得满意时,可以对其进行预览,方法是在 VBA 编辑器中选择该窗体,单 


击"运行"菜单中的三角符号"运行子过程/用户窗体",三角符号在 VBA 工具栏上也可能看得到, 


旁边是一个垂直的等于符号,最右边是个小正方形符号,它们类似于录音机上的按钮。运行窗 


体的另一个方法是按 F5 键。 


    小结:学习完本学时后,我们具备了用于程序界面设计的基本知识。我们对控件不在感到 


陌生,也明白如何向工作表和窗体添加控件,但控件的内容很多,需要边用边理解.此后,我们将 


从界面转移到学习编写代码,并最终将二者融合。让我们准备好学习编程吧! 






    3.7 疑难解答 






    问题 1.怎样决定控件的位置?如何选择添加到工作表还是添加到用户窗体? 


    解答:这完全取决于个人的爱好和应用程序的用户.如果用户对 EXCEL 非常熟悉,那么他们 


也许更希望以工作表的方式操作.在这种情况下不妨直接在工作表上创建控件;如果你的用户对 


EXCEL 不熟悉或者你需要给用户一个专业的界面感觉,那么应该使用用户窗体. 


    问题 2.什么情况下该用选项卡条而不是多页控件? 


    解答:如果每一页具有相同布局,则应选择选项卡条,否则应该选择多页. 


    本节作业 


    1.思考: 


    1)列举两种可以让用户进行多选一的控件。 


    2)如何将控件与单元格链接起来。 


    2.判断: 


    1)只有在 VBA 编辑器中才能添加用户窗体。 


    2)在 VBA 编辑器中看到的窗体网格线在运行时会自动显示。 


    3.填空:( )是显示静态文本的控件。 






                        第四课 理解变量和变量的作用 






    4.1 代码存在的位置:模块 






    VBA 代码必须存放在某个位置,这个地方就是模块。有两种基本类型的模块:标准模块和 


类模块。模块中的每个过程或者是函数过程,或者是子程序概念.本课的最后部分将讨论函数过 


程和子程序的区别。 


    新术语: 


    模块:它是作为一个单元保存在一起的 VBA 定义和过程的集合。 


    类模块:VBA 允许你创建自己的对象,对象的定义包含在类模块中。 


    你的大部分工作集中在标准模块中(简称为模块)当录制宏时如果不存在模块,EXCEL 自 


动创建一个。EXCEL 和 VBA 不关心代码存放在哪一个模块中,只要代码存在于打开的工作簿中 


即可。 






    4.2 对模块的概览 






    过程被定义为 VBA 代码的一个单元,过程中包括一系列用于执行某个任务或是进行某种计 


算的语句。工作簿的每个过程都有唯一的名字加以区分。 


    有两种不同的过程:子程序和函数过程。子程序只执行一个或多个操作,而不返回数值。 


当录制完宏查看代码时,所看到的就是子程序。宏只能录制子程序,而不能录制函数过程。一 


个子程序的例子如清单 4-1 所示。 


程序清单 4-1 子程序的例子 






                                    7 




----------------------- Page 24-----------------------


VisualBASIC 程序设计网络教学                                              橄榄树 


整                                                                     理 


Sub cmdSmallFont_Click() 


With Selection.Font 


.Name="Arial" 


.FontStyle="Regular" 


.Size=16 


End With 


End sub 


    上面列出的过程实际上是一个事件过程。通过它的名字,就可以知道这是一个事件过程。 


这个过程的名字是由一个对象的名字 CmdSmallFont 和一个事件的名字 Click 组成的,两者之间 


用下划线分开。如果还不明白,可以告诉你,CmdSmallFont 是一个命令按钮的名字。也就是说, 


当单击这个命令按钮时,就会运行这个事件过程。 


    函数过程通常情况下称为函数,要返回一个数值。这个数值通常是计算的结果或是测试的 


结果,例如 False 或 True.正如前面所说,可以用 VBA 创建自定义函数。实际上可以在工作表 


上使用你创建的函数。程序清单 4-2 是一个计算价格的 10%为运费的简单例子。 


程序清单 4-2 简单的用户定义函数示例。 


Public Function Shipping(Price) 


Shipping = Price * 0.1 


End Function 


    请注意,这个函数使用一个参数(Price).子程序和函数都可以使用参数。不论 Price 的值 


是多少,它都将决定运费额。Price 可以是数字和单元格引用。函数返回计算出来的运费,这 


个函数可以用在单元格中。 


A B 


1 Price 100 


2 Shipping =shipping(B1) 


    4.2.1 创建过程 


    创建第一个过程需要两个基本步骤。首先,需要向工作簿中添加一个模块。接着需要向模 


块中添加一个工程。对于创建的每一个应用程序,只需添加一次模块。可以使用多个模块,但 


这是不必要的。某些开发者喜欢使用多个模块,以便根据他们的目的或者窗体对过程进行组织。 


在本练习中,创建的过程只显示一个消息框。 


    在本练习中创建的过程只显示一个消息框。在本练习中使用 Msgbox 是为了提供一个可见的 


例子,虽然我们还没有介绍过 Msgbox 语句,但是在本例中将使用它。要创建该过程,请按如下 


步骤进行: 


    1)打开一个新工作簿。 


    2)选择"工具"-"宏"-"Visual Basic 编辑器",打开 VBA 编辑器窗口。 


    3)在`VBA 编辑器的左面,可以看到"工程资源管理器"窗口。在工程资源管理器窗口的 


"Thisworkbook"上单击鼠标右键,选择"插入"-"模块",这样就将一个模块添加到应用程序中了。 


(如果你没有看见"工程资源管理器"窗口,可以按 Ctrl+R) 


    4)选择"插入""过程",显示"添加过程"对话框。 


    5)输入"第一个工程"作为过程名字。在"类型"分组框中,确认选择了"子程序"。单击"确 


定"按钮。这样一个新的过程就添加到模块中了。可以在模块中看到以 Public Sub 第一个过程 


()开始,以 End Sub 结束的语句结构。 


    6)在过程中插入光标,输入以下语句并回车: 


Msgbox "这是我的第一个过程" 


在输入 Msgbox 后,会自动弹出一个消息框告诉你有关这条命令的信息,称之为自动列表技术。 


输入完成的过程如下所示: 


Public Sub 第一个过程() 


Msgbox "这是我的第一个过程" 


End Sub 


    VBA 对子程序和函数有如下的命名规则: 


    * 名字中可以包含字母数字和下划线。 


    * 名字中不能包含空格句号惊叹号,也不能包含字符@ & $ #. 


    * 名字最多可以包含 255 个字符。 






                                   8 




----------------------- Page 25-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                       理 


    4.2.2 运行宏 


    创建这个过程后,可以运行一下。运行一个过程有几种方法:可以直接使用"运行"菜单," 


运行子程序/用户窗体"工具栏按钮或按下 F5 键。要运行一个过程,可以按照如下步骤: 


    1)单击"运行子程序/用户窗体"工具栏按钮,过程执行并显示一个消息框。 


    2)单击消息框之中的"确定"按钮,关闭该消息框。 






    4.3 保存对模块所做的改变 






    要保存新过程,需要保存过程所驻留的工作簿.可以用 VBA 编辑器保存工作簿.具体步骤如 






下: 


    1)选择"文件"-"保存工作簿".因为本工作簿还没有保存过,所以要给它命名. 


    2)输入"HOUR4"作为文件名并按回车键,则工作簿和模块与过程都保存下来了. 第四课 理 


解变量和变量的作用 


Excel Home 






    4.4 变量 






    变量是用于临时保存数值的地方.每次应用程序运行时,变量可能包含不同的数值,而在程 






序运行时,变量的数值可以改变. 


    为了说明为什么需要变量,可以按照如下步骤创建一个简单的过程: 


    1)创建一个名为"你叫什么名字"的过程. 


    2)在过程中输入如下代码: 


    Inputbox "输入你的名字:" 


    现在不要担心 inputbox 语句的语法,将在第六学时中了解到有关这条命令的更多信息. 


    3)按下 F5 键运行过程,这时会显示一个输入框,要求输入你的名字. 


    4)输入你的名字并按"确定"按钮,则结束该过程. 


    你输入的名字到那里去了?如何找到用户在输入框中输入的信息?在这种情况下,需要使用 


变量来存储用户输入的结果. 


    4.4.1 变量的数据类型 


    使用变量的第一步是了解变量的数据类型.变量的数据类型控制变量允许保存何种类型的 


数据.表 4-1 列出了 VBA 支持的数据类型,还列出了各种类型的变量所需要的存储空间和能够存 


储的数值范围. 


数据类型             存储空间           数值范围 


Byte             1 字节             0 - 255 


Booleam           2 字节           True 或者 False 


Integer           2 字节           -32768 - 32767 


Long(长整型)          4 字节         -2147483648 - 2147483647 


Single             4 字节           负值范围:-3.402823E38 - -1.401298E-45 


                               正值范围:1.401298E-45 - 3.402823E38 


Double              8 字 节          负 值 范 围 :-1.79769313486232E308 - 


-494065645841247E-324 


                              正  值  范  围  :4.94065645841247E-324         - 


1.79769313486232E308 


Currency           8 字节         -922337203685477 - 922337203685477 


Decimal           14 字节         不包括小数时:+/-79228162514264337593543950335 


                              包括小数时:+/7.9228162514264337593543950335 


Date             8 字节           1000 年 1 月 1 日 - 9999 年 12 月 31 日 


Object           4 字节           任何引用对象 


String(长字符串) 10 字节+1 字节/字符              0 - 约 20 亿 


String(固定长度) 字符串的长度                    1 - 约 65400 


Varient(数字)  16 字节                       Double 范围内的任何数值 


Varient(文本)  22 字节+1 字节/字符                 数据范围和变长字符串相同 


    表 4-1 VBA 数据类型 


    作为 ABV 程序员,一个目标是选择需要存储空间尽量小的数据类型来保存所需要的数据, 


这正是表 4-1 提供各种数据类型存储空间的原因。例如,要保存诸如班级学生总数这样的小数 






                                    9 




----------------------- Page 26-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                      理 


字,那么 Byte 数据类型就足够了。在这种情况下,使用 Single 数据类型只是对计算机存储空 


间的浪费。 


    4.4.2 用 Dim 语句创建变量(声明变量) 


   现在,你对变量可以使用的数据类型已经比较熟悉了,以下我们将创建变量.创建变量可以 


使用 Dim 语句,创建变量通常成为"声明变量" Dim 语句的基本语法如下: 


    Dim 变量名 AS 数据类型 


   这条语法中的变量名代表将要创建的变量名.对变量的命名规则和对过程的命名规则相同. 


这条语句中的数据类型部分可以是表 4-1 中的任何一种数据类型. 


   变量名必须以字母开始,并且只能包含字母数字和特定的特殊字符,不能包含空格句号惊叹 


号,也不能包含字符@ & $ #.名字最大长度为 255 个字符 


   在接下来的练习中将说明如何在 VBA 中使用变量,你将要输入你的名字,并用一个消息框将 


其显示出来.具体步骤如下: 


    1)创建一个名为"显示你的名字"的子程序. 


    2)输入以下代码: 


    Public Sub 显示你的名字() 


    Dim s 名字 As String 


    s 名字 = Inputbox("请输入你的名字:") 


    Msgbox "你好"& s 名字 


    End Sub 


    3)将鼠标放到过程中的任何地方,按下 F5 键运行过程,会显示一个输入框. 


    4)输入你自己的名字并按回车键,会显示一个消息框,显示的文字中包含你自己的名字. 


    5)单击"确定"按钮,返回过程中. 


   在 Dim 语句中不必提供数据类型.如果没有数据类型,变量将被定义为 Variant 类型,因为 


VBA 中默认的数据类型是 Variant.你知道这一点后,最初的反应也许是觉得应该不用自己决定 


数据类型,而将一切抛给 VBA.这种观念是完全错误的.你必须决定选择使用何种数据类型。因为 


Variant 数据类型占用存储空间较大(16 或 22 字节)而且它将影响程序的性能。VBA 必须辨别 


Variant 类型的变量中存储了何种类型的数据。 


    4.4.3 变量命名的惯例 


    下表给出了推荐的变量命名惯例 


数据类型           短前缀          长前缀 


Array           a           ary 


Boolean         f           bin 


Byte             b           bit 


Currency         c           cur 


Double           d           dbl 






Date/Time    dt         dtm/dat 


Integer         i           int 


Long             l           lng 


Object           o           obj 


Single                      sng 


String           s           str 


Variant         v           var 


    表 4-2 变量命名的前缀 


    4.4.4 使用数组 


   如果你使用过其他编程序语言,可能对数组已经比较熟悉了.数组是具有相同数据类型并共 


同享有一个名字的一组变量的集合.数组中的元素通过索引数字加以区分,定义数组的方法如 


下: 


    Dim array_name(n) As type (其中 n 是数组元素的个数) 


    例如,如果要创建保存 10 个学生名字的数组,可以用以下语句: 


        Dim s 学生名字(9) As Integer 


   注意,括号中的数字是 9 而不是 10.这是因为在默认的情况下,第一个索引数字是 0.数组在 


处理相似信息时非常有用.假设要处理 15 门考试成绩,可以创建 15 个独立的变量,这意味着要使 


用 15 个 Dim 语句。也可以创建一个数组来保存考试成绩,具体如下: 






                                   10 




----------------------- Page 27-----------------------


VisualBASIC 程序设计网络教学                                               橄榄树 


整                                                                      理 


    Dim s 考试成绩(14) As Integer 


    声明数组时的另一种方法是不给定大小。可以在程序运行时定义其大小。通过创建动态数 


组就可以做到。例如,你的程序要创建一表格,可以提示用户输入表格的行和列的数目。声明 


动态数组的语法如下: 


    Dim dyn_array() As type 


    对数组声明后可以在程序运行时用:ReDim 语句指定数组的大小: 


    ReDim dyn_array()(array_size) 


   参数 array_size 代表数组的新大小。如果要保留数组的数值,请在 ReDim 语句后使用保留 


字 Preserve,具体语法如下: 






   ReDim Preserve dyn_array(array_size) 


    4.4.5 变量赋值 


    声明变量后就可以给变量赋值。请注意下列语句中为数组变量赋值时索引数字的使用。 


    程序清单 4-4 


    Dim i 人数 As Integer 


    Dim i 考试成绩 As Integer 


    Dim i As Integer 


    i 人数 = inputbox("输入学生的人数:") 


    ReDim Preserve i 考试成绩(i 数量) 


    For i = 1 to i 人数 


    i 考试成绩(i) = inputbox("输入考试成绩"& i ) 


    Next 






                      第五课 利用 VBA 设置工作表使用权限 






Excel Home 






一般保护工作表采取的方法是用 EXCEL 菜单中的"保护"命令,有时这尚嫌不足,比如一些机密 


文件根本要让某些使用者无法看到,但又需要他来操作工作簿中的其他表,怎么办? 


可以打开 VBA 编辑器,打开"工程资源管理器",双击该工作表,现在出现的是设置该表的属性 


的编辑窗口,单击窗口左上的下拉列表框,选择 worksheet ,这时再从该窗口右上方的列表框 


中选择 Active("激活"),这时自动显示如下的语句块: 


Private Sub Worksheet_Activate() 


End Sub 


在其中加入代码:(假设用"123"作为密码,Sheet"机密文档"为限制权限文 


档,sheet"普通文档"为工作簿中你认为任何适合的工作表) 


If Application.InputBox("请输入操作权限密码:") = 123 Then 


Range("A1").Select 


Else 


Msgbox "密码错误,即将退出!" 


Sheets("普通文档").Select 


End if 


程序如下: 


Private Sub Worksheet_Activate() 


If Application.InputBox("请输入操作权限密码:") = 123 Then 


Range("A1").Select 


Else 


MsgBox "密码错误,即将退出!" 


Sheets("普通文档").Select 


End If 


End Sub 


这样做仍有一个问题,就是越权使用者仍会看到一些文件的片段,即在提示密码的那段时间。 


好,你可以这样做,用上述方法选择工作表的 Deactivate 事件,输入以下代码: 


Sheets("机密文档").Cells.Font.ColorIndex = 2 


这 段 程 序 使 得 此 工 作 表 在 不 被 激 活 时 , 所 有 文 字 为 白 色 。 然 后 , 在 第 一 个 


程 序 中 的 


Range("A1").Select 后插入一行,写入以下代码: 






                                   11 




----------------------- Page 28-----------------------


VisualBASIC 程序设计网络教学                                             橄榄树 


整                                                                    理 






ActiveSheet.Cells.Font.ColorIndex = 56 


这段程序,在你输入正确密码后,将该表所有文字转变为深灰色。 


完整的程序如下: 


Private Sub Worksheet_Activate() 


If Application.InputBox("请输入操作权限密码:") = 123 Then 


Range("A1").Select 


Sheets("机密文档").Cells.Font.ColorIndex = 56 


Else 


MsgBox "密码错误,即将退出!" 


Sheets("普通文档").Select 


End If 


End Sub 






                       第六课 提高 Excel 中 VBA 的效率 






    由于 Microsoft Office 办公套件的广泛应用,以及该软件版本的不断提升,功能不断完善, 


在 Office 办公套件平台上开发出的的 VBA 应用程序越来越多,而 VBA 是一种宏语言,在运行速 


度上有很大的限制。因此 VBA 编程的方法直接关系到 VBA 程序运行的效率,本文列举了一些提 


高 VBA 程序运行效率的方法。 






方法 1:尽量使用 VBA 原有的属性、方法和 Worksheet 函数 






    由于 Excel 对象多达百多个,对象的属性、方法、事件多不胜数,对于初学者来说可能对 


它们不全部了解,这就产生了编程者经常编写与 Excel 对象的属性、方法相同功能的 VBA 代码 


段,而这些代码段的运行效率显然与 Excel 对象的属性、方法完成任务的速度相差甚大。例如 


用 Range 的属性 CurrentRegion 来返回 Range 对象,该对象代表当前区。(当前区指以任意空 


白行及空白列的组合为边界的区域)。同样功能的 VBA 代码需数十行。因此编程前应尽可能多地 


了解 Excel 对象的属性、方法。 


    充分利用 Worksheet 函数是提高程序运行速度的极度有效的方法。如求平均工资的例子: 


       For Each c In 


         Worksheet(1).Range(″A1:A1000″) 


    TotalValue = TotalValue + c.Value 


    Next 


    AverageValue = TotalValue / Worksheet(1).Range(″A1:A1000″).Rows.Count 


    而下面代码程序比上面例子快得多: 


     AverageValue=Application.WorksheetFunction.Average(Worksheets(1).Range( ″ 


A1:A1000″)) 


    其它函数如 Count,Counta,Countif,Match,Lookup 等等,都能代替相同功能的 VBA 程序代 


码,提高程序的运行速度。 






方法 2:尽量减少使用对象引用,尤其在循环中 






    每一个 Excel 对象的属性、方法的调用都需要通过 OLE 接口的一个或多个调用,这些 OLE 


调用都是需要时间的,减少使用对象引用能加快 VBA 代码的运行。例如 


    1.使用 With 语句。 


    Workbooks(1).Sheets(1).Range(″A1:A1000″).Font.Name=″Pay″ 


    Workbooks(1).Sheets(1).Range(″A1:A1000″).Font.FontStyle=″Bold″ ... 


  则以下语句比上面的快 


  With Workbooks(1).Sheets(1).Range(″A1:A1000″).Font 


     .Name = ″Pay″ 


     .FontStyle = ″Bold″ 


     ... 


    End With 


    2.使用对象变量。 


    如果你发现一个对象引用被多次使用,则你可以将此对象用 Set 设置为对象变量,以减少 


对对象的访问。如: 






                                   12 




----------------------- Page 29-----------------------


VisualBASIC 程序设计网络教学                                                 橄榄树 


整                                                                         理 


     Workbooks(1).Sheets(1).Range(″A1″).Value = 100 


    Workbooks(1).Sheets(1).Range(″A2″).Value = 200 


    则以下代码比上面的要快: 


   Set MySheet = Workbooks(1).Sheets(1) 






    MySheet.Range(″A1″).Value = 100 


    MySheet.Range(″A2″).Value = 200 


    3.在循环中要尽量减少对象的访问。 


    For k = 1 To 1000 


     Sheets(″Sheet1″).Select 






    Cells(k,1).Value = Cells(1,1).Value 


    Next k 


    则以下代码比上面的要快: 


    Set TheValue = Cells(1,1).Value 


    Sheets(″Sheet1″).Select 


    For k = 1 To 1000 


     Cells(k,1).Value = TheValue 


    Next k 






    方法 3:减少对象的激活和选择 






    如果你的通过录制宏来学习 VBA 的,则你的 VBA 程序里一定充满了对象的激活和选择,例 


如 Workbooks(XXX).Activate、Sheets(XXX).Select、Range(XXX).Select 等,但事实上大多数 


情况下这些操作不是必需的。例如 


    Sheets(″Sheet3″).Select 


    Range(″A1″).Value = 100 


    Range(″A2″).Value = 200 


    可改为: 


    With Sheets(″Sheet3″) 


     .Range(″A1″).Value = 100 


     .Range(″A2″).Value = 200 


    End With 






    方法 4:关闭屏幕更新 






    如果你的 VBA 程序前面三条做得比较差,则关闭屏幕更新是提高 VBA 程序运行速度的最有 


效的方法,缩短运行时间 2/3 左右。关闭屏幕更新的方法: 


   Application.ScreenUpdate = False 






    请不要忘记 VBA 程序运行结束时再将该值设回来: 


   Application.ScreenUpdate = True 






    以上是提高 VBA 运行效率的比较有效的几种方法。 






                       第七课 如何在 Excel 里使用定时器 






    用过 Excel 97 里的加载宏 "定时保存" 吗?可惜它的源程序是加密的,现在就上传一篇 


介绍实现它的文档。 


在 Office 里有个方法是 application.ontime ,具体函数如下: 






expression.OnTime(EarliestTime, Procedure, LatestTime, Schedule) 


如果想进一步了解,请参阅 Excel 的帮助。 


    这个函数是用来安排一个过程在将来的特定时间运行,(可为某个日期的指定时间,也可为 


指定的时间段之后)。通过这个函数我们就可以在 Excel 里编写自己的定时程序了。下面就举 


两个例子来说明它。 


1.在下午 17:00:00 的时候显示一个对话框。 


Sub Run_it() 






Application.OnTime TimeValue("17:00:00"), "Show_my_msg" 


'设置定时器在 17:00:00 激活,激活后运行 Show_my_msg 。 


End Sub 






                                     13 




----------------------- Page 30-----------------------


VisualBASIC 程序设计网络教学                                                  橄榄树 


整                                                                          理 


Sub Show_my_msg() 


msg = MsgBox("现在是 17:00:00 !", vbInformation, "自定义信息") 


End Sub 


2.模仿 Excel 97 里的 "自动保存宏",在这里定时 5 秒出现一次 


Sub auto_open() 


MsgBox "欢迎你,在这篇文档里,每 5 秒出现一次保存的提示!", vbInformation, "请注意! 





Call runtimer '打开文档时自动运行 


End Sub 


Sub runtimer() 


Application.OnTime Now + TimeValue("00:00:05"), "saveit" 






' Now + TimeValue("00:15:00") 指定在当前时间过 5 秒钟开始运行 Saveit 这个过程。 


End Sub 


Sub SaveIt() 


msg = MsgBox("朋友,你已经工作很久了,现在就存盘吗?" & Chr(13) _ 


& "选择是:立刻存盘" & Chr(13) _ 


& "选择否:暂不存盘" & Chr(13) _ 


& "选择取消:不再出现这个提示", vbYesNoCancel + 64, "休息一会吧!") 


'提示用户保存当前活动文档。 


If msg = vbYes Then ActiveWorkbook.Save Else If msg = vbCancel Then Exit Sub 


Call runtimer '如果用户没有选择取消就再次调用 Runtimer 


End Sub 


以上只是两个简单的例子,有兴趣的话,可以利用 Application.Ontime 这个函数写出更多更 


有用的定时程序。 






                                     14 




----------------------- Page 31-----------------------


                三、学习微软 Excel 2002 VBA 编程和 XML,ASP 技术 






   ASP已经趋于淘汰了,Vbscript将慢慢退出舞台了,其实他是vba的子集,相比vba来讲更容易 


一些,用不着深入学 






              hzg7818 


   摘自2004-3-8hhzzgg77881188版主的答复 






   作者:Julitta Korol  翻译:Tiger Chen Nov 28’ 2004 


    本书展示了Excel 2002 在标准用户界面之外什么是可行的。如果你曾经想不使用菜单来打开 


一个新的工作表,或者创建一个充分自动化的自定义窗体来收集数据和在工作表里存储结果,那么 


你必须学习一些编程。本书教你如何通过将一些费时的和重复的工作交给Excel,从而更加成果丰 


富。使用Excel内置语言,VBA (Visual Basic for Applications),你将给自己或他人带来非常高 


的自动化程度的电子表格。通过使用许多内置的编程工具,你做得可以比想象中容易得多。你不要 


增加额外费用,除非你想熟悉Excel背后的秘密。在Excel窗口下,同时按下Alt+F11,你将进入VB 


编辑器界面——Excel的编程界面。既然这个保护得很好的秘密已经公开了,就让我告诉你更多一 


些。除了VBA之外,本书还介绍了两种可以和Excel并用的热门英特网技术。一种是ASP (Active 


Server Pages),另一种是XML (Extensible Markup Language)。你也可以学习到许多其它的支持 


技术。因此,如果你真正想要获得一些热门技术,请立即购买本书,并且不要浪费时间,马上开始 


学习。Learn Microsoft Excel 2002 VBA Programming with XML and ASP 带领你从始至终创建VBA 


过程,VBScripts,ASP 页面,XML 文件和XSL 工作表。沿着这条路,有许多详细的,适用的“如 


何做”例子和插图。本书的方法是“由做而学”。本书的前面几章介绍了一些基本的VBA概念,循序 


渐进,复杂的主题在后面的章节。十七章中的每一章是按循序的。此外,本书还由四章附录,讨论 


在Excel里针对一些特殊方面的操作和编程。本书可以当作是一种在办公室或家里学习的课程。许 


多课程都有前提条件,本书也不例外。Learn Microsoft Excel 2002 VBA Programming with XML and 


ASP 不会向你介绍Excel的基本东西,例如菜单和快捷键。我们假设你已经喜欢使用Excel,并且有 


兴趣学习如何与Excel在它自己的语言里交流,学习如何将它与现在的英特网技术结合。 






                    第一章 电子表格自动化简介和了解宏命令 






         http://club.excelhome.net/dispbbs.asp?boardID=2&ID=72173&page=5 






   你准备好了增进你的微软 Excel 2002 电子表格的智能吗?通过将日常工作自动化,你可以使 


你的电子表格更快,更有效。本章带领你步入使用宏命令来加速电子表格的过程。你将学到宏是什 


么,如何以及什么时候使用它们,乃至如何编写和修改宏代码。开始学习宏命令很简单。创建宏并 


不需要什么,只是一些你已经拥有的知识——基本的微软Excel 2002 菜单知识和电子表格概念。 


你准备好开始了吗?确保你坐在计算机前并且打开了Excel 2002。 






1 了解宏 






宏是一些储存了一系列命令的程序。当你创建一个宏命令的时候,你只是将一系列的键盘输入结合 


成一个简单的命令,你以后可以“回演”这个命令。因为宏命令可以减少复杂任务的步骤,使用宏 


命令可以显著得减少你花在创建,设置格式,修改和打印工作表的时间。你可以通过Excel内置的 


录制工具来创建宏命令,也可以在代码编辑器里面直接写代码。微软 Excel 2002 电子表格具有强 


大的编程功能。 


技巧1-1:普通语言 


Excel 5 是市场上第一个使用VBA的软件。从那以后,VBA开拓了在所有微软办公应用软件中的应用。 


这意味着你从本书中学习的VBA将来同样可以应用到其它微软办公软件中,例如:Word, PowerPoint, 


Outlook or Access 






2 宏命令的普通应用 






微软 Excel 2002 带来了很多内置,节省时间的特点,这些使你工作得更快更聪明。在你决定用宏 


命令来自动化工作表任务前,确保没有现成的内置工具来做这项任务。然而,当你发现你需要反复 


地做一些动作,或者Excel没有提供一个内置工具帮你完成该任务,那么创建一个宏命令吧。宏命 


令可以使你能够将工作表的任何部分工作自动化。例如,你可以自动化数据录入——创建一个宏命 


令在工作表输入标题或者用新标签取代列标题。宏命令可以帮你检查选中的工作表区域里的重复 






                                   15 




----------------------- Page 32-----------------------


值。你可以通过宏命令快速地将格式应用到多个工作表,并且可以结合不同的格式,例如字体,颜 


色,边框和阴影等。尽管如此,Excel 还拥有非常强大的图表功能,如果你想要将图表创建和格式 


设置自动化,那么宏命令是一个好方法。宏命令也可以帮助你设置打印区域,页边距,页眉,页脚, 


以及选择特殊的打印选项。 






3 写宏之前的计划 






在你创建一个宏命令之前,花几分钟来考虑你究竟想做什么。因为宏命令是一大堆键盘输入的集合, 






事先计划你的行动非常重要。最早的计划宏命令的方法是手动地将宏命令需要做的事情做一遍。在 


你做键盘输入的同时,在一张纸上记录下他们实际发生的情况,不要漏掉任何东西。象录音机一样, 


Excel 可以将你的所有动作录制下来(译者:事实上并非如此,有些操作是无法录制的)。如果在 


录制宏之前,你没有很好地计划,你会录制很多不必要的步骤,而这些都会影响运行速度。尽管修 


改宏代码比去除录制宏里面不必要的步骤容易,但是,仅仅录制必要的步骤会节省你修改代码的时 


间和以后的麻烦。 


假设你想看一眼哪些区域是文本,哪些是数字以及哪些是公式,图1-1显示了使用不同的字体颜色 


和样式来区分这些单元格里潜在的内容。 






图1-1 


如何设置如图1-1所示的格式?打开一个含有公式计算的工作表,或者创建一个如图所示的例子。 


如果你用图示例子,请确保用SUM函数计算每月和季度的总结。 


在录制宏之前,请做如下操作: 


1. 选取一个单元格 


2. 选择“编辑”-“定位” 


3. 在“定位”对话框中,点击“特殊”按钮 


4. 在“特殊”对话框中,勾选“常数”——勾选“文本”,同时去除“数字”,“逻辑值”和“错 


    误值”的勾选 


5. 按“确定”返回工作表。注意,这时含有文本的单元格已经被选中了。小心,不要改变选中 


    区域,直到你在下一步做一些必要的格式设置 


6. 对选中区域。选择“格式”-“单元格” 


7. 在单元格格式设置对话框,选择“字体”-设置字体为“粗体”,颜色为“紫色”。然后点击 


    “确定”关闭对话框。注意,含有文本的单元格显示了不同的颜色。 


步骤1到7教你定位到文本单元格,要定位数字单元格,请按如下操作: 


8. 选取一个单元格 


9. 选择“编辑”-“定位” 


10. 在“定位”对话框中,点击“特殊”按钮 


11. 在“特殊”对话框中,勾选“常数”——勾选“数字”,同时去除“文本”,“逻辑值”和“错 


    误值”的勾选 


12. 按“确定”返回工作表。注意,这时含有数字的单元格已经被选中了。小心,不要改变选中 


    区域,直到你在下一步做一些必要的格式设置 






                                   16 




----------------------- Page 33-----------------------


13. 对选中区域。选择“格式”-“单元格” 


14. 在单元格格式设置对话框,选择“字体”-设置字体颜色为“暗蓝色”。然后点击“确定”关 


    闭对话框。注意,含有数字的单元格显示了不同的颜色。 


步骤8到14教你定位到数字单元格,要定位公式单元格,请按如下操作: 


15. 选取一个单元格 


16. 选择“编辑”-“定位” 


17. 在“定位”对话框中,点击“特殊”按钮 


18. 在“特殊”对话框中,勾选“公式” 


19. 按“确定”返回工作表。注意,这时含有公式计算结果的单元格已经被选中了。小心,不要 


    改变选中区域,直到你在下一步做一些必要的格式设置 


20. 对选中区域。选择“格式”-“单元格” 


21. 在单元格格式设置对话框,选择“字体”-设置字体为“粗体”,颜色为“红色”。然后点击 


    “确定”关闭对话框。注意,含有公式的单元格显示了不同的颜色。 


步骤15到21教你定位到公式单元格。你可以在工作表中加上图例,以便容易理解。 


22. 选取区域A1:A3,选择“插入”-“行” 


23. 选择单元格A1 


24. 选择“格式”-“单元格”,并且在“填充色”页点击“紫色”,点击“确定”返回工作表 


25. 选择B1,输入“文本” 


26. 选择单元格A2 


27. 选择“格式”-“单元格”,并且点击“暗蓝色”,“确定”返回 


28. 选择B2,输入“数字” 


29. 选择A3 


30. 选择“格式”-“单元格”,点击“红色”,“确定”返回 


31. 选择B3,输入“公式” 


32. 选择A1 


完成步骤22到32后,A1:A3单元格会显示一个简单的颜色图例,如图1-1所示。 


正如你所看到的,不管工作表显示的任务多么简单,你却可能需要很多步骤来达到预期效果。创建 


一个可以重复你刚才操作的宏命令,真的很省时间,特别是当你需要重复这个相同的工作到很多工 


作表中去。 






4 录制宏 






既然你已经知道了你需要做哪些操作,是时候打开你的宏录制器来创建你的宏了。在你依照下面的 


录制步骤之前,请确保你已经清除了刚才例子里的格式。按下Ctrl+A以选中整个工作表,选择“编 


辑”-“清除”-“格式”选择A1:A3并且选择“编辑”-“删除”。在“删除”对话框,选择“整 


行”然后点击“确定”。 


依照以下步骤来创建你的第一个宏命令: 


1. 选择一个单元格 


      录制宏之前,你应该想好是否要录制当前单元格的位置。如果你需要宏总是从一个特定的 


      位置开始,那么先打开宏录制器再选择你想要宏开始选中的特定位置。如果当前单元格的 


      位置无关紧要,那么先选择一个单元格,然后才打开宏录制器。 


   选择“工具”-“宏”-“录制新宏”。出现一个录制宏对话框。 






图1-2 当你录制新宏的时候,必须有名字。你也可以给它设置一个快捷键,储存地方以及描述。 






                                    17 




----------------------- Page 34-----------------------


2. 给宏取个名字“WhatsInACell” 


技巧1-2:宏命名 


如果你忘记给宏命名,Excel 会给出一个默认的宏名,例如:Macro1,Macro2,等等。宏名可以包 


含字母,数字和下划线,但是第一个字必须是字母(译者:中文亦可,建议用英文)。例如:Report1 


是有效的宏名,然而1Report则是非法的。宏名里不能含有空格。如果你隔开宏名中的每个词,可 


以使用下划线。例如:WhatsInACell,改为Whats_In_A_Cell。 


3. 在宏的存贮位置里,选择“当前工作簿” 


技巧1-3:保存宏 


Excel 让你可以将宏保存在三个地方: 


个人宏工作簿——如果你将宏保存在这里,你每次使用Excel 的时候都可以使用这个宏。个人宏工 


作簿在XLStart文件夹中。如果这个工作簿不存在,那么当你第一次使用这个选项的时候,Excel 


会自动生成这个工作簿。 


新工作簿——Excel将宏放在一个新工作簿里。 


当前工作簿——宏将被保存在你正在使用的工作簿里面。 


4. 在描述框里输入:显示单元格里潜在的内容:文本,数字,公式 


5. 点击“确定”关闭宏录制对话框,并开始录制。这时,出现了“停止录制”工具栏。Excel下 


    面的状态栏显示“准备录制” 






图1-3 停止录制工具栏提供按钮来停止录制,以及让Excel如何在录制宏的时候处理单元格地址 


技巧1-4:单元格地址:相对或绝对? 


绝对——如果在执行宏命令的过程中,无论哪些单元格被选中了,你都希望宏在特定的单元格执行 


这些录制的操作,那么使用绝对单元格地址。绝对单元格引用具有如下形式:$A$1,$C$5等。Excel 


宏录制器默认使用绝对引用。在录制前,确保停止录制工具栏上的第二个按钮没有被按下去。当鼠 


标指向这个按钮,工具提示“相对引用”。 


相对——如果你想要宏可以用在任何区域,就打开相对引用。相对引用具有如下形式:A1,C5等。 


在录制前,确保停止录制工具栏上的第二个按钮已经被按下去了。记住,Excel 将会继续使用相对 


引用,直到退出Excel或者再次点击相对引用按钮。在录制宏的过程中,你可以使用这两种引用方 


法。例如:你可以选择一个特定单元格(如$A$4),做一个操作,然后选择另外一个相对于当前位 


置的单元格(如C9,他在当前单元格$A$4往下5行和向右2列的位置)。当你复制单元格时,相对引 


用会自动调整引用,而绝对引用则不会。 


6. 从新进行刚才你手动完成的那些操作(参见“写宏之前的计划“) 


      录制宏的时候,只有当你按下了回车键或者点击了确定之后,你的操作才会被录制。如果 


      你按下了Esc键或者点击了取消,宏录制器不会录制任何操作。 


7. 完成所有操作后,点击停止录制工具栏上的“停止录制”按钮,或者选择“工具”-“宏” 


    -“停止录制” 






5 运行宏 






你创建了一个宏命令后,至少要运行一次以确保它运行正确。在本章的后面,你将学到好几种运行 


宏的方法,不过,现在,使用菜单命令。要看到你的成果,确保清除了例子的格式。按下Ctrl+A 


以选中整个工作表,选择“编辑”-“清除”-“格式”选择A1:A3并且选择“编辑”-“删除”。 


在“删除”对话框,选择“整行”然后点击“确定”。稍后,你将在另外一个宏里面录制清除工作 


表格式的步骤。 


1. 打开任何包含文本,数字和公式的工作表 


2. 选择“工具”-“宏”-“运行宏”来打开宏对话框 


3. 点击你要运行的宏的名称(参见图1-4) 


4. 选择“运行”,执行宏 






                                    18 




----------------------- Page 35-----------------------


图1-4 在宏对话框,你可以选择一个宏,运行,编辑或者删除它 


你也许经常会发现录制的宏不会按你预期的和你第一次操作那么运行。也许在录制宏的时候,你选 


择了错误的字体,或者忘记改变单元格颜色,或者你临时发现最好加上一个步骤。不必惊慌。Excel 


允许你修改代码,而不会强迫你重新录制那些单调的操作。 






6 修改宏代码 






你必须知道你的宏代码放在哪里,你才能找到并修改它。回想你打开宏录制器的时候,你选择了“当 






前工作簿”作为存储地址。最容易找到宏的方法是打开宏对话框,如图1-4所示。 


1. 选择“工具”-“宏” 


2. 选择宏名(本例中为WhatsInACell) 


3. 点击“编辑”按钮 


  Excel 打开一个专门的窗口,叫做Visual Basic Editor (VBE)如图1-5所示。利用快捷键Alt+F11 


可快速地在Excel表格界面和代码窗口切换。选择VBE菜单上的关闭选项可以关闭VBA代码窗口,返 


回到电子表格界面。 


代码窗口暂时看上去有些令人迷惑,不必担心。只要你开始录制宏,以及尝试写一些代码,你终将 


这个屏幕所有的组件。现在,看一下代码窗口的菜单和工具栏。这两个工具栏和Excel 窗口的菜单 


完全不同。代码窗口的菜单和工具包含一些编程和测试代码所需要的工具。只要你彻底地学习本书 


的每一章,你就会成为使用这些工具的专家。 






图1-5 VBE窗口是编辑宏命令和书写新的VBA代码的地方 


VBE窗口的主要部分是多个窗口的集合界面,这些窗口在你创建和测试VBA过程的时候是及其有用 






                                    19 




----------------------- Page 36-----------------------


的。图1-5显示了三个集合在一起的窗口:工程窗口,属性窗口和代码窗口。工程窗口显示一个开 


启的模块文件夹,在这里,模块1被选中了。Excel  录制你在工作表里的操作叫做模块1,模块2, 


等等。在本书接下来的章节里,你将利用模块来编写你自己的过程代码。模块类似于Word中的一个 


空白文档。储存每个单独模块的文件夹称为“模块” 


技巧1-5:宏还是过程? 


宏是通过内置宏录制器录制的,或者在VB编辑器里手动输入的一系列指令或函数。从Excel 5.0开 


始,“宏”经常被“过程”这个更广的概念所代替。尽管这两个词可以交替互换使用,但是,许多 


编程者更喜欢“过程”。虽然宏可以让你模仿键盘操作,真正的过程则还可以执行一些不能通过鼠 


标,键盘或者菜单来做的操作。换句话说,过程是一个更复杂的宏,它结合了传统编程语言的言语 


结构。 


代码窗口(参见图1-5)显示了下列由宏录制器录制的代码: 


Sub WhatsInACell() 





' WhatsInACell Macro 






' Macro recorded 5/31/2002 by Julitta Korol 


' Indicates the contents of the underlying cells: text, numbers, formulas. 









       Selection.SpecialCells(xlCellTypeConstants, 2).Select 






       With Selection.Font 


              .Name = "Arial" 


              .FontStyle = "Bold" 


              .Size = 10 


              .Strikethrough = False 


              .Superscript = False 


              .Subscript = False 


              .OutlineFont = False 


              .Shadow = False 


              .Underline = xlUnderlineStyleNone 


              .ColorIndex = 13 


       End With 


       Range("B6").Select 


       Selection.SpecialCells(xlCellTypeConstants, 1).Select 


       With Selection.Font 


              .Name = "Arial" 


              .FontStyle = "Regular" 


              .Size = 10 


              .Strikethrough = False 


              .Superscript = False 


              .Subscript = False 


              .OutlineFont = False 


              .Shadow = False 


              .Underline = xlUnderlineStyleNone 


              .ColorIndex = 11 


       End With 


       Range("C6").Select 


       Selection.SpecialCells(xlCellTypeFormulas, 23).Select 


       With Selection.Font 


              .Name = "Arial" 


              .FontStyle = "Bold" 


              .Size = 10 






                                           20 




----------------------- Page 37-----------------------


               .Strikethrough = False 


               .Superscript = False 


               .Subscript = False 


               .OutlineFont = False 


               .Shadow = False 


               .Underline = xlUnderlineStyleNone 


               .ColorIndex = 3 


       End With 


       Range("A1:A3").Select 


       Selection.EntireRow.Insert 


       Range("A1").Select 


       With Selection.Interior 


               .ColorIndex = 13 


               .Pattern = xlSolid 


               .PatternColorIndex = xlAutomatic 


       End With 


       Range("B1").Select 


       ActiveCell.FormulaR1C1 = "Text" 






       Range("A2").Select 


       With Selection.Interior 


               .ColorIndex = 5 


               .Pattern = xlSolid 


               .PatternColorIndex = xlAutomatic 


       End With 


       Range("B2").Select 


       ActiveCell.FormulaR1C1 = "Numbers" 


       Range("A3").Select 


       With Selection.Interior 


               .ColorIndex = 3 


               .Pattern = xlSolid 


               .PatternColorIndex = xlAutomatic 


         End With 


         Range("B3").Select 






         ActiveCell.FormulaR1C1 = "Formulas" 


         Range("B4").Select 


  End Sub 






从现在开始,让我们注重于寻找下面两个问题的答案:如何阅读宏代码?如何修改宏代码? 






7 添加注释 






看一下录制的宏代码,请注意那些开头带单引号的行。这些行就是注释。注释默认显示为绿色。执 


行宏代码时,VB会忽略这些注释行。注释经常和宏代码放在一起,来整理那些意义不甚明显的语句。 


现在,我们来给宏WhatsInACell 添加注释。 


1. 激活VBE窗口 


2. 在Selection.SpecialCells(xlCellTypeConstants, 2).Select前面点击一下,将光标移至该 


     语句开头,回车 


3. 将光标往上移一行到空白处,并且添加如下注释,注意前面有单引号(译者:英文状态下的 


     单引号) 


       ‘ Find and format cells containing text 


4. 在Selection.SpecialCells(xlCellTypeConstants, 1).Select前面点击一下,将光标移至该 






                                            21 




----------------------- Page 38-----------------------


    语句开头,回车 


5. 将光标往上移一行到空白处,并且添加如下注释,注意前面有单引号(译者:英文状态下的 


    单引号) 


      ‘ Find and format cells containing numbers 


6. 在Selection.SpecialCells(xlCellTypeFormulas, 23).Select前面点击一下,将光标移至该 


    语句开头,回车 


7. 将光标往上移一行到空白处,并且添加如下注释,注意前面有单引号(译者:英文状态下的 


    单引号) 


      ‘ Find and format cells containing formulas 


8. 在Range("A1:A3").Select前面点击一下,将光标移至该语句开头,回车 


技巧1-6:关于注释 


在VBE代码窗口里,以单引号开头的都是注释。注释的默认颜色是绿色。可以通过“选项”对话框 


(“工具”-“选项”-“编辑器格式”)更改注释颜色。注释也可以写在代码的后面。例如,在语 


句.ColorIndex = 11之后添加注释。点击该语句句末,按下Tab键,输入单引号,然后输入注释。 


显示如下: 


   .ColorIndex = 11 ' Sets the font color to Violet 






注释除了给用户提供代码目的信息之外,没有任何作用。请别忘记给你的代码写上注释。如果你几 


个月后还要回到你的代码,那么注释将帮你大忙。同样,注释可以使别人很快理解你的程序。 


9. 将光标往上移一行到空白处,并且添加如下注释,注意前面有单引号(译者:英文状态下的 


    单引号) 


      ‘Create legend 






8 分析宏代码 






所有宏过程都以关键词“Sub”开始,以关键词“End Sub”结束。在关键词“Sub”之后是宏的真 


正的名字,然后紧跟着是一对括号。在关键词Sub 和End Sub之间是那些你每次运行宏代码时VB执 


行的语句。VB从上到下读取语句,忽略那些句前带单引号的语句(参见上节关于注释的内容),读 


到End Sub时停止。请注意,录制的宏代码里包含许多停顿(译者:英文模式下的句号)。每行代码 


中都有停顿,用来连接VBA语言中不同的要素。如何阅读这种语言的用法呢?要从最后一个停顿的 


右边向左读。看看WhatsInACell里的一些语句: 


   Range("A1:A3").Select 


选择A1到A3单元格 


      Selection.EntireRow.Insert 


往选中的区域中插入行。因为前面你选中的是三个单元格(译者:应该说是占据了三行的单元格), 


VB将插入三行。 


   ActiveCell.FormulaR1C1 = "Text" 


往当前单元格里输入“Text”。因为,之前的代码是Range("B1").Select,选择单元格B1,B1是当 


前激活的单元格,所有VB往B1单元格里面输入文本。 


      With Selection.Interior 


            .ColorIndex = 3 


            .Pattern = xlSolid 


            .PatternColorIndex = xlAutomatic 


      End With 


这是一段特别的代码块,解释如下:给当前选中的单元格设置单元格填充色为红色(ColorIndex = 


3),设置填充模式为实心(xlSolid),并且给当前单元格明确为默认的填充模式(xlAutomatic)。 


这个代码块以关键词With开始,End With结束,它将加速宏代码的执行。宏代码知道走捷径,而不 


会每次都重复下面的说明: 


      Selection.Interior.ColorIndex = 3 


      Selection.Interior.Pattern = xlSolid 






      Selection.Interior.PatternColorIndex = xlAutomatic 


在关键词With后面紧跟重复的Selection.Interior,再以End With结尾。 






                                   22 




----------------------- Page 39-----------------------


9 清除宏代码 






你已经逐行解析了你宏代码,你会发现Excel录制了许多你并不想要包含进去的信息。例如,在选 






中了文本单元格后,除了设置字体为粗体和颜色为紫色之外,Excel 还录制了其它在字体页的选项 


——字体名称,字体大小,删除线,上标,下标,阴影和下划线。请看下列代码片断: 


       With Selection.Font 


              .Name = "Arial" 


              .FontStyle = "Bold" 


              .Size = 10 


              .Strikethrough = False 


              .Superscript = False 


              .Subscript = False 


              .OutlineFont = False 


              .Shadow = False 


              .Underline = xlUnderlineStyleNone 


              .ColorIndex = 13 


       End With 


如果你使用了对话框,Excel总会录制所有的设定。这些多余的代码使得你的宏代码冗长而难以理 


解。因此,你完成录制宏后,最好检查一遍你录制的代码并删除不必要的行。 


1. 在下面的代码中,删除带删除线的行: 


       With Selection.Font 


              .Name = "Arial" 


              .FontStyle = "Bold" 


              .Size = 10 


              .Strikethrough = False 


              .Superscript = False 


              .Subscript = False 


              .OutlineFont = False 


              .Shadow = False 


              .Underline = xlUnderlineStyleNone 


              .ColorIndex = 13 


       End With 


    清除后,在关键词With和End With之间只剩下了两句代码,这些才是你在录制宏的时候真正做 


    的设置: 


       With Selection.Font 


              .FontStyle = "Bold" 


              .ColorIndex = 13 


       End With 


2. 找到设置数字单元格格式的代码,依照下面的例子修改代码: 


       ' Find and format cells containing numbers 


       With Selection 






              .SpecialCells(xlCellTypeConstants, 1).Select 


              .Font.ColorIndex = 11 ' Sets the font color to Violet 






       End With 


       Range("C6").Select 


3. 找到设置公式单元格格式的代码,依照下面的例子修改代码: 


       ' Find and format cells containing formulas 


       Selection.SpecialCells(xlCellTypeFormulas, 23).Select 






       With Selection.Font 


              .FontStyle = "Bold" 


              .ColorIndex = 3 






                                           23 




----------------------- Page 40-----------------------


      End With 


4. 找到下述两行代码: 


      Range("A1:A3").Select 


      Selection.EntireRow.Insert 


5. 用下面的一句代码取代上面的两句代码: 


      Range("A1:A3").EntireRow.Insert 


注意,Excel使用了R1C1形式来设置选中单元格个公式: 


      ActiveCell.FormulaR1C1 = "Text" 


      ActiveCell.FormulaR1C1 = "Numbers" 






      ActiveCell.FormulaR1C1 = "Formulas" 


宏录制器使用了一次“ActiveCell”和一次“Selection”来选择当前单元格。这两个词都称为属 


性。你将在第二章里学习属性。当仅有一个单元格被选中时,你可以随意使用“ActiveCell”或者 


“Selection”。 






10 测试修改好的宏 






当你修改宏的时候,很可能会带入一些错误。例如,你可能会删除一行重要的代码,或者可能不注 


意清除或忽略了一个逗点(停顿)。为了确保你的宏在你修改之后还能正确地工作,你必须运行它。 


在VBE窗口,将光标放在宏代码WhatsInACell的任意行,选择“运行”-“运行模块/窗体” 


如果你在修改代码的时候,没有带入任何问题,那么宏将顺利运行,而不会有任何报错。你需要切 


换到Excel界面取看你的宏运行的结果。你可以点击任务栏,或者按Alt+F11回到Excel界面。 


如果宏在运行的过程中遇到错误,你将会看到一个对话框显示发现的错误类型。在你运行宏命令之 


前,你必须确保你的宏可以在当前激活的工作表里面运行。例如,你当前电脑上激活的时一个空的 


Excel工作表,你试图运行WhatsInACell,这时你将看到一个错误信息:“运行时间错误‘1004’- 


找不到单元格”。点击“结束”按钮,在你重新运行宏之前,确保选择了正确的工作表。 


如果选择的工作表只含有文本,你在运行WhatsInACell的时候,VB试图选择含有数字的单元格时会 


遇到同样的“找不到单元格”的错误。 


如果你忽略了With Selection.Font中的逗点,VB会出现“运行时间错误‘424’-需要对象”的信 


息。点击信息框上的“调试”按钮,你将进到代码窗口。同时,VB会进入“中断”模式,并且将有 


问题的行用黄色突出出来。在你更正代码后,VB可能会弹出信息:“这个操作将会重置你的工程, 


继续?”点击确定。尽管你可以在中断模式修改代码,但是,有些修改会终止宏的继续执行。更正 


宏代码后,重新运行它,也许你会需要解决更多的错误,之后才能顺利地运行它。你将在第二章和 


第十三章里面学到更多的关于如何处理VBA错误的方法。 






11 两个层面运行宏的方法 






你 既 可 以 在 Excel 界 面 运 行 宏 , 也 可 以 在 VB 编 辑 器 界 面 运 行 它 。 当 你 从 VB 






编 辑 器 屏 幕 执 行 


WhatsInACell时,VB在屏幕之后执行这些代码。你看不到VB选择和设置格式,也看不到VB插入三空 


行做图例。为了观察到VB的执行情况,你必须在Excel界面,通过选择“工具”-“宏”,或者将你 


Excel界面和VB编辑器界面同时显示在电脑屏幕上(参见图1-6) 






                                  24 




----------------------- Page 41-----------------------


图1-6 如果你从VB编辑器运行宏时,想观察宏的运行情况,你必须将Excel界面和VB编辑器并排地 


布置在一起 


按照下列步骤来并排布置你的Excel界面和VB编辑器界面: 


1. 在任务栏上的空白处单击右键。任务栏在屏幕的下端,“开始”按钮的位置。 


2. 下列菜单中,选择“纵向平铺窗口” 


3. 最小化那些不需要的窗口,重复步骤1 


4. 现在,两个窗口并排显示了,点击代码的任意位置,然后按下“F5”(或者选择“运行”-“运 


    行模块/窗体”)。坐好,观察你录制的宏在运行,不是很激动吗?稍后,你将学习如何将VB慢 


    慢运行,这样你 就可以一步一步地观察宏代码的运行情况。 






12 完善你的宏代码 






录制宏后,你可能会发现宏可以进行一些别的操作。如果你已经熟悉了VB语言,要往宏里面加指令 






并不是一件困难的事情。然而,在绝大多数情况下,你可以将这些工作交给Excel宏录制器,从而 


更有效地完成这项工作。你也许会说,Excel录制了太多的不需要的指令。但是,肯定的是,宏录 


制器不会犯错,你完全可以依赖于它。 


如果你想要通过宏录制器在你的代码里添加指令,那么你必须录制一个新宏,然后复制需要的部分 


再粘贴到原来代码的正确位置。 


我们来给A1:B3添加粗边框: 


1. 激活图1-6看到的Excel界面 


2. 选择“工具”-“宏”-“录制新宏” 


3. 在宏对话框点击确定,接受默认的宏名并开始录制 


4. 选择区域A1:B3 


5. 选择“格式”-“单元格”,点击“边框”页 


6. 在“边框样式”部分,点击“外部”按钮 


7. 在边框粗细列表,点击最粗的,再点击确定关闭对话框 






                                    25 




----------------------- Page 42-----------------------


8. 点击单元格A1。注意,A1:B3区域有了粗边框。 


9. 点击“停止录制”按钮,或者选择“工具”-“宏”-“停止录制” 


切换置VB编辑器窗口,查看你录制的宏。给A1:B3(译者:原文为A1:A3)添加粗边框的代码如下: 


       Sub Macro2() 


       ' 


       ' Macro2 Macro 


       ' Macro recorded 5/31/2002 by Julitta Korol 






       ' 


       ' 


              Range("A1:B3").Select 


              Selection.Borders(xlDiagonalDown).LineStyle = xlNone 






              Selection.Borders(xlDiagonalUp).LineStyle = xlNone 


              With Selection.Borders(xlEdgeLeft) 


                     .LineStyle = xlContinuous 


                     .Weight = xlThick 


                     .ColorIndex = xlAutomatic 


              End With 


              With Selection.Borders(xlEdgeTop) 


                     .LineStyle = xlContinuous 


                     .Weight = xlThick 


                     .ColorIndex = xlAutomatic 


              End With 


              With Selection.Borders(xlEdgeBottom) 






                     .LineStyle = xlContinuous 


                     .Weight = xlThick 


                     .ColorIndex = xlAutomatic 


              End With 


              With Selection.Borders(xlEdgeRight) 






                     .LineStyle = xlContinuous 


                     .Weight = xlThick 


                     .ColorIndex = xlAutomatic 


              End With 


              Selection.Borders(xlInsideVertical).LineStyle = xlNone 






              Selection.Borders(xlInsideHorizontal).LineStyle = xlNone 


              Range("A1").Select 


       End Sub 


现在,我们来分析一下这些录制的代码。你认为你可以去掉其中的一些指令吗?在你删除这些不必 


要的代码之前,考虑使用注释。在你删除任何代码之前,请将它们注释掉,然后运行宏。如果VB 


没有出现任何错误信息,那么你就可以安全地删除这些被注释了的代码。如果每次都按照这个指导 


思想,你就不会重复录制相同的操作了。如果这个宏命令没有正确地运行,那么你需要去掉刚才的 


注释,毕竟,这些代码可能是必须的。关于注释的详细信息,参见第二章。 


当你使用宏录制器来创建宏的时候,你可以很快地掌握Excel菜单选项和对话框设置在VBA里的等同 


方法。然后,你可以在在线帮助里面查找这些VB指令的意思和用法。很显然,VB要执行越多的指令, 


宏运行的速度就越慢。去掉那些无关紧要的命令会加速宏的运行。然而,为了使你的代码容易理解, 


你需要戴上你的侦探帽子,寻求最佳途径。例如,看一下你录制的给选中的单元格加外框的宏。看 


上去,宏录制器是在分别地给每一条线进行设置。VB没有一个简单的一句命令来给选中的区域加外 


边框,这似乎很难理解。学习任何语言中正确的词语和表达是很费时的。时间一长,你会发现VB 


实际上有一个另外的方法BorderAround让你在单元格区域添加边框和设置颜色,线型和新边框的粗 


细。下面的语句是VBA中给选中的单元格设置外围粗边框的最佳方法: 






    Range("A1:B3").BorderAround Weight:=xlThick 






                                          26 




----------------------- Page 43-----------------------


上面的指令使用Range对象的BorderAround方法。它给A1:B3区域添加了一个粗线外框。(下一章涵 


盖了VB对象,属性和方法)。 


现在我们将上面的指令加到宏WhatsInACell里面去: 


1. 激活含有宏WhatsInACell的代码窗口 


2. 在ActiveCell.FormulaR1C1 = "Formulas"之后插入一行 


3. 在空白行加入以下指令: 


      Range("A1:B3").BorderAround Weight:=xlThick 4 






4. 光标放在宏代码的任何位置,按F5运行修改好的代码。 


技巧1-7:附加指令 


要在现存的代码中添加指令的话,通过在需要的位置按回车键加入空白行,并且输入必要的VB语句。 


如果附加指令是键盘操作或菜单命令的话,你可以使用宏录制器来创建必要的代码,然后将它们复 


制粘贴到原来的宏里面。 


假设你想要VB在执行完最后一行代码时给你提示,这种操作是不可能被录制下来的,因为Excel没 


有相应的菜单选项。但是,你可以手动使用VB语言在你的代码里面添加指令。 


1. 在代码窗口下,在End Sub前回车 


2. 光标放在空白行,输入下列语句: 


   MsgBox "所有操作都已完成。"(译者:英文状态下的引号。) 


3. 确保光标在代码里,按下F5 


4. VB执行完最后一个指令后,弹出这个信息。点击确定。你现在知道宏已经运行完成。 


MsgBox是用得非常频繁的VBA函数之一,你将在第四章中学习它的使用。 






13 重新命名宏 






在代码里面添加了一些代码后,为了更好地反映这个宏的目的,你需要将其改名。过程的名称应该 


越接近它的功能越好。你不需要按任何键就可以更改宏名。在代码窗口,你将关键词Sub后面老的 


宏名清除,并且打入新的名称即可。 






14 运行宏的其它方法 






到现在为止,你已经学习了运行宏的方法。你已经知道通过选择“工具”-“宏”-“运行宏”来 


运行宏。不幸的是,如果你需要经常运行宏,这种方法是不方便的。你也可以在VB编辑器窗口使用 


快捷键F5或者通过选择“运行”-“运行模块/窗体”来运行宏。此外,你还可以在VB编辑器窗口 


点击标准工具栏上的按钮来运行宏(见图1-7)。 






图1-7 VB过程可以通过标准工具栏来运行 






15 使用键盘快捷键运行宏 






流行的方法是通过设置一个快捷键来运行宏。按Ctrl+Shift+D比从宏对话框激活宏要容易得多。你 


必须给宏设置一个快捷键,之后才能使用它。 


1. 按Alt+F8快速打开宏对话框 


2. 点击宏清单里的WhatsInACell,然后选择选项按钮 


3. 弹出宏选项对话框,如图1-8。光标定位在快捷键文本框里 


4. 按下Shift键和键盘是的字母I。Excel录制下了快捷键Ctrl+Shift+I 


5. 点击确定以关闭宏选项对话框 


6. 点击取消返回工作表。试试用你刚设置的快捷键来运行宏,确保激活了Excel窗口,然后按下 


    Ctrl+Shift+I 






                                   27 




----------------------- Page 44-----------------------


图1-8 使用宏选项对话框设置键盘快捷键来运行宏 


技巧1-8:避免快捷键冲突 


如果你给宏设置的快捷键和Excel内置的快捷键冲突,而且你打开的又正是含有那个宏的工作表, 


那么按下该快捷键后Excel会运行你自己的宏。 






16 通过菜单运行宏 






如果你宁愿通过菜单来运行宏,那么你可以将你的宏做成一个菜单选项。使用“自定义菜单”对话 


框,你可以快速的将你的宏命令加入到任何Excel的内置菜单中。 


1. 在Excel界面工具栏的空白处,单击右键,选择“自定义菜单” 


2. 在自定义菜单对话框选择“命令”页 


3. 在“类别”清单里选择“宏” 






图1-9 创建自定义菜单(第一步) 


4. 将“自定义菜单”拖曳至工具菜单里去。当工具菜单展开时,你可以将按钮放在任意地方。 


    图1-10显示了自定义菜单在工具菜单的最下面。 






                                    28 




----------------------- Page 45-----------------------


图1-10 创建自定义菜单(第二步),你可以将自定义菜单放在Excel菜单里,也可以放在子菜单里 


5. 在菜单项上单击右键,并且在快捷菜单“名称”的文本框里,将其改成你想要的名字(参见 


    图1-11)。例如,将名称改为“Contents of Ce&lls”。连接符用以表示键盘快捷键。将连接 


    符放在你想显示下划线的字符之前。这个自定义菜单将会显示为“Contents of Cells”,注 


    意,菜单里面字与字之间可以有空格。 


6. 选择最后一个选项(快捷菜单上)——“指定宏”(参见图1-11)。在宏对话框,选择宏 


    “WhatsInACell”,点击确定,关闭自定义菜单对话框。 


    现在,你的宏可以通过自定义菜单来运行了。如果你没有给自定义菜单选项指定宏就关闭了 


    这个快捷菜单,Excel在你第一次试图使用这个自定义菜单选项时会提示你要宏名。 


7. 选择“工具”-“Contents of Cells”,或者按Alt+T和l来运行宏。如果你在做上述操作时, 


    清除了内置菜单或菜单选项,可以打开自定义菜单对话框,点击工具页,然后选择“重置” 


    按钮就可以恢复了。然而,这样操作后,会恢复Excel默认设置,你的自定义菜单选项也不复 


    存在了。 






                                   29 




----------------------- Page 46-----------------------


图1-11 创建自定义菜单(第三步)你可以使用快捷菜单给菜单选择重命名,已经设置你自己的宏。 


你必须先打开自定义菜单,才能使用该快捷菜单 






17 通过工具栏按钮运行宏 






如果你喜欢使用工具栏里的按钮,你可以轻易地在任何工具栏里添加按钮,并且指定你自己的宏。 


我们来添加WhatsInACell到工具栏去。 


1. 选择“工具”-“自定义” 


2. 在自定义对话框,点击“命令”页 


3. 在类别清单里选择宏 


4. 拖曳“自定义按钮”图标到工具栏的任何地方。在本例中,这个按钮放在标准工具条中格式 


    刷的右边。 


5. 修改按钮的工具提示:在按钮上单击右键,然后在出现的快捷菜单的名称选项中,编辑名称 


    文本。本例中,将工具提示改为“Contents of Ce&lls” 


6. 修改按钮图标:在按钮上单击右键,并且选择“修改按钮图标”,出现42个Excel预先设计的 


    图标供你选择。本例中,用铅笔图标取代了默认的图标 


7. 给按钮指定宏:在按钮上单击右键,并且选择“指定宏” 


8. 选择“WhatsInACell”点击确定 


9. 点击关闭,关闭自定义对话框 


10. 光标指向你刚才创建的自定义按钮上,按钮的旁边显示工具提示“Contents of Cells”(参 


    见图1-12)。点击按钮运行宏 






                                   30 




----------------------- Page 47-----------------------


图1-12 你可以在任何工具栏添加自定义按钮来运行宏 






18 通过工作表里面的按钮运行宏 






在本书后面,你将学习如何在工作表中添加按钮,帮助Excel初学者做数据输入。现在,我们来过 


一遍如何将宏WhatsInACell指定在一个工作表的按钮上。 


1. 激活含有数据的工作表 


2. 选择“视图”-“工具栏”,并且选择“窗体”。窗体工具栏出现了,如图1-13 






图1-13 你可以将宏指定给一个工作表里的按钮 


3. 在窗体工具栏上点击按钮 


4. 在工作表任意地方点击一下 


5. 当出现指定宏对话框时,选择宏名(WhatsInACell)然后点击确定 


6. 改变按钮1的名称:确保选中了按钮,并且输入名称“Contents of Cells”。按钮被选中后, 


    它就像图1-13里显示的一样。如果选择的符号没有显示,在按钮上单击右键,并且在快捷菜 


    单上选择“编辑文本”,选择默认的文字,然后输入新的名称 


7. 按钮重命名后,在工作表按钮之外的任何地方点击一下退出按钮编辑状态 


8. 点击你刚才创建的按钮,运行宏 






                                    31 




----------------------- Page 48-----------------------


图1-14 控件工具箱的默认工具 


技巧1-9 往工作表里添加控件 


你可以使用窗体工具栏往工作表里添加控件(参见图1-13),也可以使用控件工具箱(参见图1- 


14)。两种工具栏都可以通过视图选择工具栏选项来获得。 


窗体里的控件和Excel的早期版本(5.0,7.0和97)兼容,并且可以用在图表,老的XLM宏表和所有 


你想通过点击控件来运行宏的工作表里。 


控件工具箱里的控件就是人们熟知的ActiveX控件。你可以将ActiveX控件放在工作表或者你用VB 


编辑器创建的窗体上。然而,窗体工具栏上的控件只对点击(Click)事件反应,ActiveX控件则有 


许多行为,或者说事件,发生于你使用它的时候。 


当你使用窗体控件时,你给它指定宏。这个宏时储存在本工作表,新工作表或者个人宏工作簿的一 


个模块里。当你使用ActiveX控件时,书写的宏代码时储存在控件本身的。 






19 保存宏 






在这章中,你创建的宏WhatsInACell位于一个Excel工作表中。你需要保存这个开启了的工作表来 






保存这个宏。我建议你将其保存为Chap01.xls。保存后,关闭它,然后打开一个新工作表。注意, 


你工具栏上的自定义按钮还在那儿,正如工具菜单里的Contents of Cells样还在那儿一。在你使 


用这些工具运行宏之前,请在单元格A1里输入“Addition”,A2里输入数字2,A3里输入数字4,已 


经A4里输入“=SUM(A2:A3)”。当你运行这个宏时,Excel会打开适当的工作表并且执行这个指定给 


自定义工具的过程。 






20 打印宏 






如果你要将你的宏归档起来,或者在你离开电脑的时候研究宏代码,你就需要打印宏。你可以打印 


你储存宏的整个模块,也可以打印选择的行。 


打印含有宏的整个模块: 


1. 将光标放在模块的任意地方 


2. 选择“文件”-“打印” 


3. 在打印-VBA对话框,选择“当前模块” 


4. 点击确定打印模块 


打印选中的文本: 


1. 在模块里,选择你要打印的文本 


2. 选择“文件”-“打印” 


3. 在打印-VBA对话框,选择“选择” 


4. 点击确定打印选中的文本 






21 保存宏在个人宏工作簿 






当你录制宏时,可以将它保存在个人宏工作簿里面。当你储存宏在个人宏工作簿里时,Excel创建 


一个名为“Personal.xls”的文件并且放在“Program Files\Microsoft Office\Office”的子文 


件夹——XLStart文件夹里。保存在XLStart文件夹的文件每次在Excel启动的时候都会自动打开。 






                                    32 




----------------------- Page 49-----------------------


个人宏工作簿是一个保存通用宏代码的方便的地方,就像下面这个宏。现在来录制一个通用的宏 


“FormulasOnOff”。这个宏的目的是设置是否显示工作簿的公式。 


1. 选择“工具”-“宏”-“录制新宏” 


2. 在录制宏对话框,输入宏名“FormulasOnOff” 


3. 在保存宏的下拉菜单里选择“个人宏工作簿” 


4. 点击快捷键文本框,并且按下“Shift+F” 


5. 选择确定退出录制宏对话框 


6. 按下“Ctrl+~”打开公式的显示,或者选择“工具”-“选项”并且点击“视图”页上“窗 


    口选项”中的“公式”检验盒。当你打开公式显示时,工作簿单元格里显示的是公式,而非 


    这个公式计算出来的数值。如果你是在一个空白工作表中录制这个宏的,那么你将注意到的 


    唯一变化是工作表的列宽。 


7. 点击“停止录制”,或者选择“工具”-“宏”-“停止录制” 


8. 查看代码:按下Alt+F11,或者选择“工具”-“宏”-“VB编辑器” 


这时,VB编辑器屏幕上的工程窗口里显示了一个多出来的VBA工程(Personal.xls)。点击这个过程 


名左边的加号来打开这个工程。这个VBA工程包含两个文件夹:Excel对象和模块。点击模块文件夹 


的加号来打开它,然后双击模块1。这时代码窗口显示了宏FormulasOnOff的内容(参见图1-15)。 


每个Excel工作表只有一个工程。你第一次录制宏的时候,Excel创建一个模块文件夹,并且将你的 


代码储存在模块1里面。如果你在相同的工作表里录制另一个宏,Excel将其放在前一个录制的宏的 


同一个模块1的下面。相同工作时间录制的所有的宏都储存在相同的模块里面。但是,如果你关闭 


Excel,然后再重新这个工作簿,Excel就会将它储存在一个新的模块。 






图1-15 在工程浏览器窗口,你可以选择你需要的工程 


录制宏的时候,你打开了公式的显示。这个宏的名称表明可以切换公式显示的开和关。你必须修改 


代码才能确保它按照这种方式运行。 


                                    33 




----------------------- Page 50-----------------------


录制的宏设置当前窗口显示公式为真: 


ActiveWindow.DisplayFormulas = True 


设置为“False”将关闭公式的显示: 


ActiveWindow.DisplayFormulas = False 






为了在VBA里设置转换,你需要按照下面的方法来连接两语句: 


ActiveWindow.DisplayFormulas = Not ActiveWindow.DisplayFormulas 


用上面的语句代替你录制的代码,并且运行这个宏。无论你运行多少次,这个宏总是知道做什么。 


你可以使用相同的思路来创建代码以切换格式线或其它Excel特点的显示与否。当你关闭Excel时, 


它会提示你保存个人宏工作簿的变化,点击确定以保存变化。当你重启Excel,个人宏工作簿会在 


后台自动开启。 


如果你想要在个人宏工作簿里保存其它的宏,你可以选择下列方法中的一个: 


  录制一个新宏,并且选择个人宏工作簿来储存 


  切换到VB编辑器,打开你要移动到个人宏工作簿里去的宏,剪切这个宏,并且打开个人宏工作 


   簿。将宏粘贴到已经存在的模块中,或者创建一个新模块再粘贴 


  选择“文件”-“导入文件”……从另外一个VB工程(*.frm,*.bas,*.cls)导入宏代码 






22 打开含有宏的工作簿 






无论何时你打开一个含有宏的工作簿,Excel显示一个警告信息,如图1-16。为了避免显示这个警 


告信息,你可以通过安全对话框关闭病毒保护(参见图1-17)。 


当病毒信息出现时,你可以选择: 


  取消宏——当你打开一个来源不熟悉的含有宏的工作簿,例如因特网,电子邮件,为了保护你 


   的电脑不被宏病毒破坏,你应该选择“取消宏”。工作簿打开时不会运行它里面的任何宏。如果 


   没有密码保护的话,你就可以切换到VB编辑窗口查看代码。查看代码后(译者:如果代码安全), 


   你可以关闭该工作簿,然后重新打开它并且启用宏。 






图1-16 如果你打开了病毒保护,当工作簿含有宏时,Excel 会弹出一个警告信息 


  启用宏——你如果指定这个工作簿来自于一个可靠的来源,也含有有用的宏,点击启用宏按钮。 


  更多信息——在你决定取消或者启用宏时,如果你需要了解更多的信息,那么点击这个按钮。 


   Excel 2002 有一个有用的功能让你自动取消所有没有签名并且来源不明的宏。选择“工具”- 


   “宏”-“安全”进入这个功能。 


当你创建一个需要给别人使用的宏时,你可以使用VB编辑器工具菜单里的数字签名来确认这个宏不 


会带来病毒。宏的数字签名正如在纸上的签名。请在Excel在线帮助里搜索如何安装和创建你自己 


的数字签名。输入“数字签名”就可以获得相关主题。 






                                   34 




----------------------- Page 51-----------------------


图-17 选择中间的选项,让你根据工作簿决定是否取消或者启用宏 






23VB 编辑窗口 






现在,你已经知道如何录制,运行和修改宏了,让我们花些时间来熟悉VB编辑器的一些特点。使用 


VB编辑器上的工具,你能够: 


  编写你自己的宏过程 


  创建自定义窗体 


  查看和修改对象属性 


  测试VBA过程和定位错误 


有两种方法进入VB编辑器: 


  从Excel界面的工具菜单:选择“工具”-“宏”-“宏编辑器” 


  从键盘:按下Alt+F11 


  (译者:在工作表标签上单击右键,然后选择查看代码) 






24 了解工程浏览窗口 






工程窗口显示当前打开的工程和它的组成部分清单。VBA工程包括下列组成: 


  工作表 


  图表 


  当前工作簿——工程储存的工作簿 


  模块 


  类模块——特殊的模块让你可以创建自己的对象 


  窗体 


  引用到其它工程 


通过工程浏览器,你可以管理你的工程,容易地在当前打开的工程中切换。 


你可以通过三种途径激活工程浏览器: 


  通过视图菜单,选择工程浏览器 


  通过键盘,按下Ctrl+R 


  通过工具栏,点击工程浏览器按钮(参见图1-18) 


工程浏览器有三个按钮。左边第一个按钮(查看代码)显示当前选中的模块(译者:或者窗体)里 


的代码窗口。中间那个按钮(查看对象)显示Excel界面当前工作表,或者窗体文件夹里面的窗体。 


右边的按钮(切换文件夹)隐藏或者显示工程浏览器里的文件夹。 






                                    35 




----------------------- Page 52-----------------------


图-18 标准工具栏上的按钮提供了快速的方式进入许多VB特征 






25 了解属性窗口 






属性窗口让你查看你工程里的对象和设置它们的属性。当前选中的对象的名称就显示在属性窗口的 


标题栏下面的对象栏。对象的属性可以按照字母顺序查看,也可以按类别查看(参见图1-19)。 






图1-19 属性窗口显示的是当前被选中的对象的属性设置 


  字母顺序——按字母顺序地列出被选择的对象的所有属性。通过选择属性名,并且输入或者选 


   择新的设置,来更改属性设置。 


  类别——按类别列出被选中的对象的所有属性。你可以将清单折叠起来,查看类别,你也可以 


   展开类别查看属性。类别名称左边的加号(+)说明这个类别可以展开。减号(-)说明这个 


   类别已经展开。 


有三种方式可以进入属性窗口: 


  视图菜单,选择属性窗口 


  从键盘,按下F4 


  从工具栏,点击属性窗口按钮(参见图1-18) 






26 了解代码窗口 






代码窗口是用来VB编程的,也是用来查看,修改录制的宏代码和现存的VBA工程的。每个模块会以 


一个专门的窗口打开。有好几个方法可以激活代码窗口: 


  从工程浏览器窗口,选择你要的用户窗体或者模块,然后点击查看代码按钮 


  从菜单,选择“视图”-“代码” 






                                    36 




----------------------- Page 53-----------------------


  从键盘,按下F7 


在代码窗口的上面,有两个下拉清单列表(参见图-20),方面你快速地移动到任意代码处。在代 


码窗口左上角的对象列表框,你可以选择你想查看代码的对象。你可以在代码窗口右上角的列表框 


里选择一个过程或者事件过程查看代码。当你打开这个列表框,这个模块里的所有过程名按字母顺 


序排列在那儿。如果你选择了一个过程,光标就会跳到那个过程的第一行处。 


将列分工具条(参见图1-20)拖曳下列,你就可以将代码窗口分为两半了(参见图1-21)。 






图1-20 代码窗口有几个部分,使得定位过程和查看代码变得很轻松 


你可以查看不同的代码部分了。这样设置代码窗口,目的是方便在同一个模块内的过程里复制或剪 


切,并且粘贴代码片断。只要简单地将列分工具条拖曳至代码窗口上面就行。代码窗口的底部有两 


个图标。点击“过程查看”图标,代码窗口里一次只显示一个过程,可以通过过程/事件列表框选 


择另外的过程。点击“全部模块查看”则可以显示这个模块里的所有过程。使用竖向滚动条可以在 


代码中滚动。 


页边指示工具条是在修改代码和调试是提供一些帮助指示的。如果你想快速查看关于指示的信息, 


请看第十三章。 






                                    37 




----------------------- Page 54-----------------------


图1-21 你可以将代码窗口列分为两个窗口来查看长过程 






27 VB 编辑器里的其它窗口 






除了代码窗口,VB环境下还有很多其它窗口频繁地被使用: 


窗体窗口用来创建自定义对话框和用户窗体。 






图1-22 在选项里,你可以选择显示哪些窗口 


你将在第十章里学习到更多的这类知识。 


图1-22显示了一些可以显示了VB编辑器里的窗口清单。你将在第二章里(对象浏览器,立即窗口) 






                                    38 




----------------------- Page 55-----------------------


和在第三章里(当地窗口,观察窗口)学习如何使用这些窗口。 






28 接下来…… 






通过一些电子表格自动化的例子,你不但已经如何录制宏,而且也已经学习了如何查看,阅读和修 


改VB代码。还有,你也尝试了用许多方法运行。最后,你还快速过了一遍VB编辑器窗口。 


在下一章,我们将会给你介绍VBA基础,你将学习许多新术语,更重要的是,你将获得有用的VBA 


词汇表,这将帮你将更多的任务交给Excel帮你完成。 






                              第二章 VBA 第一步 






作者:Julitta Korol  翻译:Tiger Chen Nov 28’ 2004 


语言学习是一个长期的活动,在此过程中,你会经历不同的阶段,由生疏到熟悉。学习VBA编程也 


是一样的,没有捷径。要想精通VBA,你必须从一个初级阶段起步(第二至四章)。只有当你对VBA 


后面的一些基本的东西有了很好的理解之后,才能提高到中级阶段(第五至七章)和高级阶段(第 


八至十七章)。但是,重要的事情先来。在你能够用VBA自由自在地控制Excel之前,你需要获得一 


些你的术语和语法。在VB里,如何表达这些?“在工作簿里添加一个新工作表”,“删除单元格A5 


的内容”,“将单元格A1的公式复制到单元格B1”?你也许知道这些单个的词语,然而,你怎么知道 


如何将它们正确地组合在一起,Excel才能执行这些任务?你将在本章中学习VBA的术语和规则。 






1 了解指令,模块和过程 






在第一章,你学习到了Excel宏录制器创建的一系列指令是和你实际进行的操作完全等同的。这些 


指令自动地放在工作簿里一个叫做“模块”的表里。Excel将模块储存在模块文件夹里,这个文件 


夹在当前工作簿,新工作簿或者个人宏工作簿里面。你必须激活VB编辑器窗口,并且双击工程浏览 


器里的模块文件夹才能查看到这些模块。当模块表在代码窗口里打开了后,你才能最后分析你的过 


程代码。 


所有录制的指令都包括在“过程”里面。过程里面的每一行都是一个“指令”。指令的类型有很多 


中,例如,关键词,运算符,或者其它过程的调用。“关键词”代表VB中的一个特殊的意义。在第 


一章中,你学习了最常见的VBA关键词——Sub 和End Sub,它们表示一个过程的开始和结束。关键 


词默认地显示为蓝色。你不要将这些术语做其它的目的,因为关键词已经被VB保护了。 


除了关键词,VB指令里还可以有运算符。运算符有四种类型:算术运算,字符串连接,逻辑运算和 


比较运算。“运算符”允许你将某些值结合起来。例如,减号运算符(/)可以用来计算总数的百分 


比。本书中,你有很多机会看到如何在VBA过程中使用运算符。 


VB指令的另外一种类型是过程调用。过程调用让你快速地跳到其它过程并且执行其它指令。是不是 


很难想象?让我们看一下你在第一章中录制的宏WhatsInACell。 假设你也需要包含同一模块中宏 


FormulasOnOff中的一些语句。怎么做呢?你可以复制需要的代码行,再粘贴过去。然而,有一种 


更简单快速的方法。你可以调用这个过程,而不需要在两个过程中复制。例如,你想VB在遇到指令 


MsgBox "所有操作都已完成"之前执行宏FormulasOnOff里面的指令,只要添加下面一句代码就行: 


FormulasOnOff 


当VB到达这一行,它就会立即跳到FormulasOnOff过程并且执行它的代码。之后,它会回到宏 


WhatsInACell去执行剩下的代码,遇到关键词End Sub时则停止。 


在你尝试这个例子之前,你必须学会如何给VBA过程和模块命名,已经如何调用不同工程里的过程。 






2 VBA 工程命名 






工程是一套Excel对象,模块,窗体和引用。除了VBAProject这个位于工程浏览器中工作簿名称之 


前默认名称,每个工程需要一个独特的名称。我们来给VBAProject (Chap01.xls) 和 VBAProject 


(Personal.xls)命名: 


1. 启动Excel,打开Chap01.xls,这里储存了宏WhatsInACell代码。你录制了宏FormulasOnOff的 


   个人宏工作簿会自动开启 


2. 切换到VB编辑器窗口 


3. 选择VBAProject (Chap01.xls) 


4. 双击属性窗口里的名称属性,这个操作选中了默认的工程名称VBAProject 


5. 输入“FirstSteps”作为该VBA工程的名称,回车。注意,工程浏览器现在显示的是名称是 






                                    39 




----------------------- Page 56-----------------------


   FirstSteps (Chap01.xls) 


6. 在工程浏览窗口选择VBAProject (Personal.xls) 


7. 双击属性里的名称属性 


8. 输入“Personal”作为它的名称,回车 


技巧2-1 避免名称冲突 


为了避免VBA工程之间的命名冲突,请给你的工程独特的名称。你可以使用下述方法之一来更改工 


程名称: 


  在工程浏览器窗口,选择工程名称,双击属性窗口里的名称属性,再输入新的名称 


  在工程浏览器窗口,在工程名称上单击右键,并且选择“工程名称属性”。出现如图2-1显示的 


   工程属性对话框,在工程名称文本框里面输入新的名称 






图2-1 工程属性窗口可以用来更改当前被选中的工程名称和描述 






3 模块重命名 






当你录制宏或者创建新的过程时,VB会创建一个模块文件夹来储存你的VBA 代码。 第一个文件夹 






叫“模块1”,第二个叫“模块2”,等等。你打开一个新的工作簿并且创建VBA工程时,新VBA工程里 


的模块文件夹又会命名为“模块1”,“模块2”,等等。模块拥有相同的名称不但对你,而且对VB造 


成很大混淆,因为,它要在一个打开许多工程的环境中执行你的宏或工程。 


为了避免模块混淆,给FirstSteps (Chap01.xls) 工程和 Personal (Personal.xls) 工程里的“模 


块1”重新命名: 


1. 在工程浏览器窗口,选择FirstSteps (Chap01.xls)工程,并且选择“模块1” 


2. 双击属性窗口里的名称属性,这个动作选中了模块的默认名称“模块1” 


3. 输入“WorksheetFormatting”作为模块1的名称,并且回车。注意,工程浏览器窗口现在显示 


   的模块名称是“WorksheetFormatting” 


4. 在工程浏览器窗口选择Personal (Personal.xls) 


5. 双击属性窗口里的名称属性 


6. 输入“Switches”作为模块1的名称,回车 






                                   40 




----------------------- Page 57-----------------------


图2-2 工程浏览器窗口显示通过属性窗口给工程和模块设置的独特名称 






4 从其它工程调用过程 






你只要明确过程名称,就可以调用这个在同一个工程里任何模块里的过程。假设过程FormulasOnOff 


和宏WhatsInACell在同一个工程里的不同模块(或者同一个模块),在WhatsInACell宏里面调用过 


程FormulasOnOff,你所要做的所有工作只是明确过程名称,示例如下: 


Sub WhatsInACell() 


      <这里是你录制的指令> 


      FormulasOnOff 


End Sub 


然而,如果两个或者两个以上的模块含有这个相同的过程名称,你除了要明确过程名称外,还必须 


包括模块名称。假设工程FirstSteps (Chap01.xls)有三个模块。模块FormulaFormatting包含宏 


WhatsInACell,但是,模块Switches和模块Formulas都含有一个叫FormulasOnOff的宏。如何在 


WhatsInACell调用FormulasOnOff(模块Switches里面的)?请看下面例子: 


Sub WhatsInACell() 


      <这里是你录制的指令> 


      Switches.FormulasOnOff 


End Sub 


要调用其它工程里的过程,你必须建立对该工程的引用。你可以在“引用”对话框进行这些操作。 


因为FormulasOnOff在Personal (Personal.xls)工程里,在你能够从WhatsInACell调用它之前,你 


需要添加对“Personal”的引用。下面是几种建立引用的方法: 


1. 在工程浏览器窗口,点击FirstSteps (Chap01.xls) 


2. 选择“工具”-“引用” 


3. 在引用对话框,选中“Personal”旁边的勾选框(参见图2-3),然后点击确定(译者:在截图 


   前,我并没有保存Personal,所以在附图里没有Personal一行,如果你依照书中一步一步走下 


   来,应该没有问题) 






                                    41 




----------------------- Page 58-----------------------


图2-3 引用对话框列出了所有这个工程可以引用的工程。如果你想要执行其它工程里的过程,你 


就必须建立对这个工程的引用 


既然对“Personal”工程的引用已经建立了,我们就来从WhatsInACell里调用FormulasOnOff吧。 


1. 在工程浏览器窗口,选择FirstSteps (Chap01.xls)并且定位到含有WhatsInACell的模块 


2. 在MsgBox "所有操作都已完成"之前增加一空白行,并且输入代码:FormulasOnOff 


3. 返回到Excel界面,确保当前工作表是这个例子数据(参见第一章的图1-1) 


4. 使用任何你在第一章里学到的方法来运行宏WhatsInACell 


如果你给两个不同工程里的不同过程以相同的名称,那么你必须明确工程名称才能调用它。 


我们假设FirstSteps (Chap01.xls)工程和Personal (Personal.xls) 工程里都有叫FormulasOnOff 


的宏,要调用Personal (Personal.xls)工程里的FormulasOnOff(记住,你已经必须先建立对 


Personal的引用),必须包括工程名称: 


Sub WhatsInACell ( ) 


      <这里是你录制的指令> 


      Personal.Switches.FormulasOnOff 


End Sub 


技巧2-2 VB如何定位被调用的过程 


当你调用一个过程,VB先在主调方(WhatsInACell)的同一个模块里查找。如果没有找到被调过程 


(FormulasOnOff),VB就会在同一个工程的其它模块里查找。如果还是找不到,VB则会检查对其它 


工程的引用。 


技巧2-3 工程名称不在引用对话框 


如果你想要调用一个当前关闭的工程里的过程,当你打开引用对话框试图建立引用时,这个过程名 


称不在清单中。点击“浏览”,并且打开被调用过程所在的文件夹。添加引用的对话框默认地列出 


数据库文件(*.olb, .tlb, .dll)。从文件类型的下拉清单中选择Excel文件(*.xls, *.xla),选 


择并打开含有你要调用过程的文件。这个工程的名称将会加在引用对话框的最后一行。 






5 了解对象,属性和方法 






使用VBA,你可以创建工程控制Excel的许多东西,你同样也可以控制很多其它的应用程序。VB的伟 


大来自于它的控制和管理各种各样的对象的能力。但是,“对象”是什么呢?“对象”是你通过VBA 


控制的东西。工作簿,工作表,工作表里的单元格区域,图表或者工具条,这些只是一些用Excel 


时想要控制的东西的举例。这些东西就是对象。Excel含有超出一百种你可以通过不同方式操作的 


对象。所有的VB对象都被分层归类。一些对象本身又可能含有其它的对象,例如,Excel时一个应 


用对象,这个应用对象包含其它对象,例如工作簿或者命令条。工作簿对象可能包含其它对象,如 






                                   42 




----------------------- Page 59-----------------------


工作表或者图表。你将在本章种学习如何控制以下Excel对象:区域,窗口,工作表,工作簿和应 


用。我将“区域”列在了第一位置,有一个非常重要的原因,如果你不知道如何操作单元格区域的 


话,你基本上不能用电子表格来做什么。 


某些对象看上去相似。如果你打开一个新工作簿,检查它的工作表,你不会发现什么不同。一组相 


似的对象被称为“集合”。例如,工作表的集合包含所有具体工作簿中的工作表;命令条的集合包 


含所有的工具条和菜单。集合同样是对象。Excel中使用得最频繁的集合是表(Sheets)集合,它 


代表所有的工作表和图表,还有工作簿集合,工作表集合以及窗口集合。当你使用集合时,相同的 


动作可以在这个集合中所有的对象上执行。 


每一种对象都有一些特征供你描述。在VB里,这些对象的特征被称为“属性”。例如,工作簿对象 


有名称属性;区域对象有列,字体,公式,名称,行,样式和值等属性。这些对象属性是可以设置 


的。你通过设置对象的属性控制对象的外观和位置。对象属性一次只能设置为一个特定的值。例如, 


当前工作簿不可能同时有两个不同的名称。VB中最难理解的部分是有些属性同时又可以是对象。想 


想区域(Range)对象,你可以通过设置字体颜色来改变选定单元格的外观。但是,字体(Font) 


可以有不同的名称(Times New Roman, Arial, …),不同的字号(10,12,14,…)和不同的样 


式(粗体,斜体,下划线,…)。这些是字体的属性。如果字体有属性,那么字体也是对象。 


属性真是了不起,让你改变对象的外观,但是,如何控制这些操作呢?你在使Excel为你执行任务 


之前,你需要知道另外一个术语。对象有方法。每一种你想要对象做的操作都被称为“方法”。最 


重要的VB方法是Add方法。你可以使用这个方法添加一个新工作簿或者工作表。对象可以使用不同 


的方法。例如,区域(Range)对象有专门的方法让你清除单元格内容(ClearContents方法), 清 


除格式(ClearFormats方法)以及同时清除内容和格式(Clear方法)。还有让你选择,复制或移动 


对象的方法。方法有可选择的参数确定方法执行的具体方式。例如,工作簿(Workbook)对象有一 


个叫关闭(Close)的方法。你可以使用它关闭任何打开了的工作簿。如果工作簿有改动,Excel 


会弹出一个信息,问你是否要保存变化。你可以使用关闭方法和设定它的保存变化(SaveChanges) 


参数为假(False)来关闭这个工作簿并且不管它的任何变化。正如例子: 


Workbooks("Chap01.XLS").Close SaveChanges:=False 






6 学习对象,属性和方法 






当你学习新的事物时,理论会给你必须的背景,但是,你如何真正知道那是什么呢?大多数人习惯 


形象思维,为了使Excel对象易于理解,VB在线帮助提供了一个对象模型,请看接下来的附图。注 


意,Application对象位于树型图的最上端,它实际上代表Excel本身。其它对象在较低的层次。 


假设你想要控制Range对象,在你能够控制任何Excel对象之前,你必须对它创建引用。为了获得下 


图中的Range对象,只要遵照下面几行代码。每次看到树型图中的线指向不同的层时,你只要巧妙 


地将线换成一个逗点运算符(停顿,英文状态下的句号)。这样,最终你会以下面的方式到达Range 


对象: 






Application.Workbook.Worksheet.Range 


你可以使用Excel对象树型图来寻找到其它对象的路径,例如窗口(Window),批注(Comment),自 


动筛选(AutoFilter)或者绘图区(ChartArea)。分析对象模型是一个学习Excel对象的非常好的 


方法。你花在这里的时间,以后你开始编写VBA过程的时候,会给你加倍的回报。通常,你需要明 


确你引用的对象的名称。 


现在,我们来点更具体的。假设你要清除单元格A4里的内容。手动做这个时,只要选择单元格A4 


然后按下键盘上的Delete键就可以了。用VB做同样的操作,你首先需要知道如何使Excel选中了正 


确的单元格。单元格A4和其它的工作表单元格一样,是Range对象。VB没有Delete方法来清除单元 


格内容,取而代之的是ClearContents方法,例如: 


Range("A4").ClearContents 


注意在对象名称和方法之间的逗点运算符。这个指令去除单元格A4里的内容。然而,如何使Excel 


清除工作簿Chap02.xls第一个工作表里单元格A4的内容呢?我们仍然假设打开了好几个工作簿。 






                                   43 




----------------------- Page 60-----------------------


图2-4 Excel对象树型图(第一页)(译者:原书图2-5(工作簿对象树型图)已包含在内,故在 


此略过) 


如果你不希望最后在错误的工作簿或工作表里删除了A4里的内容,那么你必须写下详细的指令,这 


样VB就知道在哪里找这个单元格: 






Application.Workbooks("Chap02.xls").Worksheets("Sheet1") .Range("A4").ClearContents 


上面的指令应该写成一行,并且应该从右到左阅读:清除单元格A4里的内容,这个单元格在一个叫 


“Sheet1”的工作表里,而这个工作表又在一个叫“Chap02.xls”的工作簿里面,工作簿“Chap02.xls” 


又应该是Excel应用程序的一部分。注意,集合名称的后面带有一个字母“s”:Workbooks和 


Worksheets。所有引用的工作簿,工作表或单元格名称都必须用引号(译者:英文状态的引号)包 


括起来。 


如何找到Excel对象树型图?选择Excel界面上的“帮助”- “Excel帮助”-“编程信息”-“微 


软Excel VB参考”-“Excel对象模型”。(译者:2002版有全局的对象模型,2003版好像没有这个。) 


除了Excel对象,你还可以使用Office,Forms和DAO,ADO对象模型。属于这些数据库(library) 


中的对象都可以用在Excel中,也可以用在Office家族中的其它应用软件中。在十五章,你可以看 


到使用DAO和ADO对象,从Excel进入Access数据库的例子。 






                                  44 




----------------------- Page 61-----------------------


图2-6 Excel对象(Worksheet) 


技巧2-4 VBA 和 Excel 的早期版本 


Excel在线帮助列出了Excel对象模型从早期版本以来的变化。许多对象,属性和方法都已经被更新 


的,改进的特色所代替了。为了提供兼容性,被取代的对象已经被隐藏起来了(译者:它们仍然是 


可用的)。打开VB编辑器窗口上的在线帮助,隐藏的对象同样可以在对象浏览器里找到。如果你在 


对象浏览器窗口上单击右键,你可以选择显示隐藏成员的选项。你将在以后的章节中学习如何使用 


对象浏览器。 






7 句法和文法 






既然现在你已经知道了VBA的一些基本组成要素(对象,属性和方法),是时间开始使用它们了。但 


是,你怎么将对象,属性和方法连接成正确的语言结构呢?每种语言都有语法规则,人们必须遵循 


语法以确保他们被理解了。无论你说的是英语,西班牙语,法语还是其它语言,你在读,写的时候 


都必须遵从一定的规则。在编程中,我们使用“句法”(syntax)这个术语来更确切地明确它的语 


言规则。你可以在在线帮助或者在对象浏览器窗口查找每个对象,属性或方法的句法。下面列出一 


些你必须的VB常用规则: 


  规则1:引用对象的属性 


如果这个属性没有自变量,使用下面的句法: 


Object.Property 






                                    45 




----------------------- Page 62-----------------------


对象是一个占位符,是你放置你想要进入的实际对象名称的地方。属性同样也是一个占位符,你可 


以在这里放置该对象的特点。例如:指向工作表中单元格A4中输入的值,见下述指令: 


Range("A4").Value 


注意对象名称和属性之间的句号。当你需要进入一个存在于多个其它对象里的对象的属性时,你必 


须按顺序地写上所有对象的名称,并且用 句号运算符分开。例如: 


ActiveSheet.Shapes(2).Line.Weight 


这个例子指向当前工作表里图形(Shapes)集合里的第二个对象里的直线(Line)对象的粗细 


(Weight)属性。 


有些属性要求一个或多个自变量。例如,使用偏移(Offset)属性,你可以选择一个和当前单元格 


相对位置的单元格。Offset属性需要两个自变量,第一个自变量为行号(rowOffset)第二个是列 


号(columnOffset)。 


  对象        属性 自变量 


ActiveCell.Offset(3, 2) 


在上面的例子中,假设当前单元格是A1,Offset(3, 2)将会指向往下3行和往右两列的单元格,也 


就是单元格C4。因为,在括号内的自变量总是很难理解,通常操作是将它们的名称也列上,见下例: 


ActiveCell.Offset(rowOffset:=3, columnOffset:=2) 






注意,自变量名称后面总是跟着一个冒号和一个等于号(:=)。如果你使用带名称的自变量,你可 


以任意顺序地列出它们,上面的指令也可以写成这样: 






ActiveCell.Offset(columnOffset:=2, rowOffset:=3) 


改后的指令没有改变意思,你仍然指向单元格C4。然而,如果你改变ActiveCell.Offset(3, 2)中 


自变量的次序,结果你会指向D3,而不是C4。 


  规则2:改变对象的属性 


Object.Property = Value 


Value是一个新的你要赋给该对象属性的值。这个值可以是: 


     一个数字 


   Range("A4").Value = 25 


   上面的指令在当前工作表的单元格A4里输入数字25 


     在引号里的文本 


   ActiveCell.Font.Name = "Times New Roman" 


   上面的指令将当前单元格字体改为Times New Roman 


     逻辑值(True或False) 


   ActiveCell.Font.Bold = True 


   上面的指令设置当前单元格的字体为粗体。 


  规则3:返回对象属性的当前值 


Variable = Object.Property 


Variable(变量)是VB将要储存属性设置的地方的名称,你将在第三章里学习关于变量的知识。 


  变量          对象             属性 


CellValue = Range(“A4”).Value 


上面的指令将当前A4单元格里的值保存到变量CellValue。 


  规则4:指向对象的方法 


如果该方法没有自变量,那么句法应该是: 


Object.Method 


对象是一个占位符,是你放置你想要进入的实际对象名称的地方。方法同样也是一个占位符,你可 


以在这里放置要对该对象的进行的操作的名称。例如,可以使用下述指令来清除单元格A4的格式(译 


者:应该是内容): 


对象             方法 


Range("A4").ClearContents 


如果该方法可以使用自变量来限制,那么句法为: 


Object.Method (argument1, argument2, … argumentN) 


例如,使用GoTo方法,你可以快速地选择工作表里的任何区域。GoTo方法的句法为: 






                                   46 




----------------------- Page 63-----------------------


Object.GoTo(Reference, Scroll)  ‘对象.GoTo(参照, 窗口滚动) 


Reference自变量是目标单元格或者区域,Scroll自变量可以设定为真(True)让Excel窗口滚动到 


该目标地址出现在窗口的左上角;或者设定为假(False),窗口不滚动(译者:系统默认为False)。 


例如,下面的VBA语句选择工作表Sheet1里的单元格P100,并且窗口滚动: 


Application.GoTo _ 


      Reference:=Worksheets("Sheet1").Range("P100"), _ 


      Scroll:=True 


上面的指令没有固定在一行,使用了一条特殊的线(下划线)将它分为几段。下面的部分将讲述这 


个。 






8 打断很长的 VBA 语句 






尽管一行VBA代码最多可以包含1024个字母,但是,为了使你个过程容易阅读,最好将长的语句打 


断为两行甚至多行。VB使用一个专门的连续线(下划线)置于一行代码的末尾,表明下一行是这行 


的连续。例如: 


Selection.PasteSpecial _ 


      Paste:=xlValues, _ 


      Operation:=xlMultiply, _ 


      SkipBlanks: =False, _ 


      Transpose:=False 


这个连续符是下划线,你必须在下划线之后带一个空格。 


你可以在下述几种情况中使用连续符: 


  运算符之前或者之后。例如:&,+,Like,NOT,AND 


  逗号之前或者之后 


  冒号和等号(:=)之前或者之后 


  等号之前或者之后 


你不可以在冒号和等于号之间使用连续符,例如,下面的代码VB是不认的: 


Selection.PasteSpecial Paste: _ 


      =xlValues, Operation: _ 


      =xlMultiply, SkipBlanks: _ 


      =False, Transpose: _ 


      =False Selection.PasteSpecial Paste: _ 






      =xlValues, Operation: _ 


      =xlMultiply, SkipBlanks: _ 


      =False, Transpose: _ 


      =False 


同样,在引号之内的文本之间加连续符也是不对的,例如,下面的下划线的使用是无效的: 






MsgBox "To continue the long instruction, use the _ 


      line continuation character." 


上面的指令应该打断为如下代码: 


MsgBox "To continue the long instruction, use the " & _ 


      "line continuation character." 






9 了解 VBA 错误 






在编写或编辑VBA过程之中,无论你多名小心,出错的可能性还是很打的。例如,你可以错误拼写 


一语句,放错了一个逗号或引号,或者忘记了一个句号或右括号。这些类型的错误称为句法错误。 


幸运的是,VB比较容易帮助你发现这种类型的错误。为了让VB在你输入一行代码后,自动帮你检测 


语法的正确性,你需要在VB窗口的“工具”-“选项”里,确保勾选了“编辑器”页上的“自动语 


法检测”。 






                                     47 




----------------------- Page 64-----------------------


图2-7 选项对话框的编辑器上的“自动语法检测”帮你检查VBA过程里的打字错误 


当VB发现语法错误时,弹出一个错误信息框,并且将有误的代码行颜色变为红色(参见图2-8)或 


者其它在选项对话框“编辑器格式”页设定的颜色。如果错误信息框上的解释不够清楚,你总是可 


以点击“帮助”按钮寻求更多的帮助。再如果VB在线帮助无法给你提供正确的方向,那么返回你的 


程序,仔细检查有误的那行代码是否漏掉了字母,引号,句号,冒号,等于号,左括号和右括号等。 






图2-8 这个错误由于漏掉了常数xlCellType前面的括号而产生 






                                   48 




----------------------- Page 65-----------------------


图2-9 当VB试图在工作表或单元格区域里选择一个并不存在的单元格时,就会产生一个运行时间 


错误 


查找语法错误可能是烦人的并且费时的事情。有些语法错误只有在过程运行的时候才能被发现。在 


试图运行你的过程的时候,VB可能找到那种因为使用了无效的自变量,或者是漏掉了那些需要成对 


使用的指令如If语句和循环结构,而造成的错误。 


技巧2-5:程序调试 


你很可能不只一次听过“计算机程序里充满了错误”。在编程里,错误就被称为“bug”(错误,漏 


洞),而“调试”(debug)则是给你的程序除错的过程。调试的第一步就是改正所有的语法错误。 


VB提供了无数种工具,你可以使用它们来追踪和消除错误。在本章中,你将知道如何使用VB助手帮 


助你在编写程序时出现尽可能少的错误;在第十三章中,你将学习如何使用专门的调试工具来捕获 


你VBA程序里的错误。 


除了语法错误外,还有其它两种错误:运行时间和逻辑。运行时间错误发生在过程运行的时候。图 


2-9显示了一种典型的运行时间错误。运行时间错误经常发生在那些程序员在编写代码的时候没有 


想到的情况。例如,当程序试图访问一个用户电脑上并不存在的驱动器或者文件,或者没有首先检 


查是否用户插入软盘并关闭软驱口而试图复制一个文件到软盘,这时就会发生运行时间错误。 


第三种错误——逻辑错误,通常不会发出明确的错误信息。过程可能没有语法错误,甚至运行无误, 


然而,得到的却是错误的结果。逻辑错误通常非常难以查找,并且它藏得很隐秘,间歇发生,你不 


能指望花几个小时,甚至几天,就能找到错误源。 






10 查找帮助 






当你使用宏录制器时,你所有的操作都被翻译成VBA指令,并且放置在一个模块里。你在研究这些 


录制的过程时,不要忘记帮助随时可用。你会发现有些代码的意思可能会非常易懂,然而,有效却 


不怎么明白。这时候,你就需要寻求帮助了。当你独自工作时,只要轻轻一点或者轻轻一按就可以 


请教你的VBA老师了。使用VB在线帮助比使用词典或参考手册要快捷和容易得多。如果你讨厌一页 


一页地在词典里找你需要的术语,你将惊讶于你如何快地从VB代码窗口找到需要的帮助页面。 


让我们来检查你如何通过内置的VBA老师的帮助,将WhatsInACell过程里的第一句变成你自己的VBA 


词汇: 






Selection.SpecialCells(xlCellTypeConstants, 2).Select 


上面的指令可以打断为三部分,哪些部分?Selection是对象还是属性?SpecialCells是什么? 


Select是什么?要回答这些问题,请依照下面的操作: 


1. 激活你要分析的过程的代码窗口 


2. 点击你不懂的词语 


3. 按下F1 






                                   49 




----------------------- Page 66-----------------------


图2-10 VBA的对象,属性和方法在在线帮助里解释得很详细 


帮助就会显示相应的页面。如果你的光标放在词语“Selection”中间,你就会知道Selection可以 


是 一 个 应 用 程 序 的 属 性 , 也 可 以 是 一 个 窗 口 对 象 。 如 果 你 的 光 标 在 下 一 个 不 明 


白 的 术 语 


(SpecialCells)并且按上面的步骤再做一遍后,你将看到SpecialCells帮助屏幕(参见图2-10)。 


注意,每个帮助主题包含许多信息。被查找的指令类型显示在帮助窗口的上面;指令的类型允许词 


语分类。例如,SpecialCells是方法,可以使用这个方法的对象名称列在“应用于”下面(译者: 


点击“应用于”,出现对象名称列表)。指令名称下面的“参阅”和“示例”让你快速地跳到其它应 


用或意义相似的指令,以及查看使用这个指令的例子。指令的意义显示在“参阅”和“示例”标题 


的下面。接下来则是语法和需要的自变量和其它参数。“说明”部分给出一些推荐使用该指令的情 


形。 


你可以很容易地将示例中的代码复制到你的过程中去:选中你要复制的代码行,按下Ctrl+C,或者 


单击右键,选择快捷菜单上的“复制”,然后切换到VB代码窗口,点击你需要粘贴代码的地方,再 


按下Ctrl+V或者选择“编辑”-“粘贴”。 






11 语法和编程快捷助手 






VB编辑器窗口上的“编辑”工具条上有很多按钮,帮助你快速容易地输入正确格式的VBA指令。如 


果“编辑”工具条目前在VB编辑器窗口上不可连接,那么你可以选择“视图”-“工具条” 






图2-11 编辑工具条上的按钮使得编写程序和设置指令格式变得很容易 






                                  50 




----------------------- Page 67-----------------------


在VB中编写过程需要你使用成百上千的内置指令和函数。因为大多数人们无法学习所有VBA里可用 


指令的语法,IntelliSense提供了你所需求的语法和编程帮助。当你在代码窗口编程时,经常会有 


专门的窗口弹出来,引导你完成正确的VBA代码。 






12 属性/方法列表 






每个对象都会有许多属性和方法。当你输入一个对象名称和一个句号以分开这个对象名称和它的属 


性或方法时,弹出一个列表菜单。这个菜单列出了在这个句号之前的对象的所有可用的属性和方法 


(参见图2-12)。如何打开这个自动工具?选择“工具”-“选项”,单击选项对话框上的“编辑 


器”页,确保勾选上“自动列出成员”。 






图2-12 在输入VBA指令时,VB会建议可以用于该对象的属性和方法 


如何从弹出菜单(图2-12)上选择项目?试图输入你需要的属性或方法名称的前几个字母,当Excel 


突出显示了正确的项目名称,则回车,插入该项目到你的代码中去,并且开始新的一行;或者,你 


需要在同一行继续写代码,那么就按Tab键代替回车。你也可以双击该项目来插入到代码中去。只 


要按Esc键就可以关闭这个弹出菜单,而不插入任何项目。当你按Esc键取消了弹出菜单后,VB将不 


会对同样的对象显示该菜单。你可以通过以下方法来再次显示属性/方法弹出菜单: 


  按Ctrl+J 


  使用“backspace”(后退)键删除句号,然后重新输入句号 


  在代码窗口上单击右键(该对象,句号后),并且在快捷菜单上选择“属性/方法列表” 


  选择“编辑”-“属性/方法列表” 


  点击“编辑器”工具条上的“属性/方法列表”按钮 






13 常数列表 






本章的前面,你学习了给属性赋值,需要使用下面规则: 


Object.Property = Value 


如果选项对话框(编辑器页)已经勾选了“自动列出成员”,Excel就会在等号前的属性弹出一个菜 


单,列出该对属性有效的常数。常数是表明确切的描述或者结果的值。Excel和Office里面的其它 


应用软件都有很多预先定义的内置常数。你将在第三章中学习常数,常数类型和使用。 


假设你需要你的程序打开Excel工作表上的分页预览。“编辑”(译者:视图)菜单上有两个选择: 


普通视图和分页预览。普通视图是绝大多数Excel任务的默认视图模式;分页预览则是编辑视图, 


显示工作表中有内容的区域。这两种选项都有相应的内置常数来表示。Excel常数起名总是以“xl” 


开头。你一旦在代码窗口里输入指令: 


ActiveWindow.View = 


就会弹出一个菜单,列出这个属性的有效常数名称。使用在上节中“属性/方法列表”弹出菜单同 


样的技术,也可以处理“常数列表”弹出菜单。按下Ctrl+Shift+J或者点击“编辑器”工具条上的 


“常数列表”按钮,可以激活常数列表菜单。 






                                   51 




----------------------- Page 68-----------------------


图2-13 常数列表弹出菜单显示了对敲入的属性有效的常数清单 






14 参数信息 






如果你有过使用Excel函数的经历,你就会知道许多函数需要一个或者多个自变量(或者参数)。如 






果VB函数要求自变量,你可以在输入左括号后在光标下面看到一个提示框,显示必要的或可选的自 


变量的名称(参见图2-14)。参数信息帮你很容易地给VBA函数设置参数。另外,它提醒你其它两 


件对函数运行正确至关重要的事情:自变量的顺序和自变量要求的数据类型。你将在下一章里学习 


数据类型。 


在代码窗口里面输入下述代码,看看参数信息是如何工作的: 


ActiveWorkbook.SaveAs( 






图2-14 A tip window displays a list of arguments utilized by a VBA function or instruction. 






你一旦输入了开始的括号,光标的下面就会出现一个提示框,当前的自变量会显示为粗体;当你输 


入完第一个自变量并且输入了逗号,VB会将下一个自变量为粗体。可选的自变量会用中括号[ ]括 


起来。只要按下Esc键就可以关闭参数信息窗口。如何使用键盘来打开提示窗口?输入指令或函数, 


紧接着是左括号,然后按下Ctrl+Shift+I。你也可以点击编辑菜单上的参数信息按钮或者选择“编 


辑”-“参数信息”。 






15 快速信息 






当你选择了代码窗口里的指令,函数,方法,过程名称或者常数,然后点击编辑工具条上的“快速 


信息”按钮(或者按下Ctrl+I),VB将会显示突出显示项目的语法和常数的值。快速信息可以通过 


选项对话框来打开或者关闭。在编辑器页,勾选“自动显示快速信息”,打开快速信息功能。 






图2-15 快速信息提供函数参数清单,也可以是常数值和VBA语句语法 






16 自动完成关键字 






加速在代码窗口编写VBA程序的另一种方法是使用“自动完成关键字”功能。当你输入一个关键字 


的前几个字母,然后按下Ctrl+空格键,或者点击编辑工具条上的“自动完成关键字”按钮,VB会 


帮你输入这个关键字的剩余字母,节约你的时间。例如,在代码窗口里输入关键字“Application” 


的前四个字母,并且按下Ctrl+空格键: 


Appl 


                                    52 




----------------------- Page 69-----------------------


VB将会完成剩余的字母,在Appl地方,你将看到整个关键字Application。如果有好几个关键字具 


有相同的开头字母,当你按下Ctrl+空格键后,VB会显示一个弹出菜单,列出所有关键字。测试这 


个例子,可以输入关键字Application的前三个字母,按工具条上的自动完成关键字按钮,然后在 


弹出菜单上选取合适的关键字。 






17 缩进/凸出 






也许你已经看到,在选项对话框的编辑器页上有许多设置你可以打开以使用代码窗口许多可用的自 






动功能。如果勾选了“自动缩进”选项,你就可以自动缩进所选的代码行,缩进的量为“Tab宽度” 


文本框里的数字。默认的自动缩进量是4个字母,你也可以在文本框里输入一个新的数字来改变Tab 


宽度。你为什么需要在代码里使用缩进?缩进可以使你的代码更容易阅读和理解。特别是输入一些 


做决定或重复性工作的代码行时,更建议使用缩进。你将在第五和第六章中学习如何创建这种类型 


的VB指令。现在,我们来练习使用缩进和凸出代码行,用第一章里的宏WhatsInACell作为例子: 


1. 在工程浏览器窗口,选择FirstSteps(Chap01.xls)工程,并且激活含有WhatsInACell代码的 


   WorksheetFormatting模块 


2. 选择开始为关键字With和结束为End With的一段代码 


3. 点击编辑工具条上的缩进按钮,或者按键盘上的Tab键(译者:按Tab键需要将光标放在行首, 


   而非选中指令) 


4. 选中的指令会向右移动4个字母的位置,如果使用了Tab宽度的默认设置。 


5. 点击编辑工具条上的“凸出”按钮,或者按Shift+Tab将选中的指令行返回原来的位置。 


缩进和凸出同样可以在编辑菜单里找到。 






18 设置注释块/解除注释块 






在第一章中,你学习了一行代码前面加一个引号表示注释。注释不但使代码更容易理解,而且它在 


VBA过程的测试和处理问题中都是很有用的。例如,你执行一个过程时,它可能和期望的运行不一 


致,对于那些可能产生问题的代码行,你现在想略过它们,但是以后可能还需要用到它们,你就可 


以在它们前面加一个引号注释掉它们,而不必删除它们。对大多数人来说,需要注释掉一行代码的 


话,只有在它前面敲入一个引号就可以了,但是,如果要注释掉整块代码,使用“编辑”工具条上 


的“设置注释块”和“解除注释块”按钮则是很方便的。要注释掉几行代码,只要选中这些代码行 


并且点击“设置注释块”按钮。点击“解除注释块”按钮,将注释掉的代码恢复到代码里。 


如果你没有选中文本,就点击了“设置注释块”按钮,只有在光标所在的代码行前面加入引号。 






19 使用对象浏览器 






如果你想要在VBA众多的组件和功能中自由切换,那么使用对象浏览器。这个专门的内置工具在VB 


编辑器窗口是可用的。使用下面任何一种方法都可以访问对象浏览器: 






                                    53 




----------------------- Page 70-----------------------


图2-16 对象浏览器让你在当前VBA工程里可用的所有对象,属性和方法里浏览 


  按F2 


  选择“视图”-“对象浏览器” 


  点击工具条上的“对象浏览器”按钮 


对象浏览器让你浏览VBA过程中可用的对象,也可以查看它们的属性,方法和事件。在对象浏览器 


的帮助下,你可以在VBA工程的多个过程之间快速移动。 


对象浏览器分为三部分(参见图2-16)。窗口的上部显示“工程/库”下拉列表,这里列出了所有 


库名称以及当前VBA工程里可用的所有工程名称。库是包含一个应用程序里对象的信息的专门文件。 


新的库可以通过“引用”对话框(“工具”-“引用”)来添加。<所有库>列出了你电脑上安装了的 


所有库中的所有对象。当你选择一个叫“Excel”的库时,仅仅能在Excel里执行的对象名称才能被 


看到。和Excel库相反,VBA库列出了所有能在VBA里执行的对象名称。 


在“工程/库”下拉列表框下面,有一个“搜索”文本框,让你可以快速地在某个库里搜索你的信 


息。这个地方会记住你最近搜索的四个项目。在对象浏览器的任何地方单击右键,在快捷菜单上选 


择“全字匹配”,你就可以只搜索匹配整个字的内容。对象浏览器上的“搜索结果”(参见图2-16 


和2-17)显示符合搜索条件的库,类和成员。当你输入搜索文本并且单击搜索按钮,VB展开对象 


浏览器对话框以显示搜索结果。你可以点击“望远镜”按钮右边的“显示/隐藏搜索结果”来显示 


或者隐藏搜索结果。 






                                   54 




----------------------- Page 71-----------------------


图2-17 在对象浏览器里搜索答案 


类列表框显示所选中的库里面所有可用的对象类,如果你选择VBA工程,列表显示该工程里的对象。 


在图2-16里,CommandBarComboBox 对象类被选中了。当你选中一个类,右边的列表(成员)显示 


该类可用的属性,方法和事件。图2-16上显示了类CommandBarComboBox的一些成员。成员默认地 


按字母顺序列出。然而,你可以使用对象浏览器快捷菜单上的“组成员”来组织这些成员列表(属 


性,方法或事件)。如果你选择“工程/库”里面的VBA工程,成员列表框列出该工程里的所有过程。 


双击该过程名称,就可以进入该过程并检查其代码。如果你选择类“VBA”,你将看到VB内置的函数 


和常数。如果你对所选的类或成员需要更多的信息,可以点击对象浏览器窗口上面的问号按钮。对 


象浏览器下面的窗口显示所选成员的代码格式。如果你点击代码格式里绿色的连接部分,你将跳到 


对象浏览器窗口的所选成员的类或库。代码格式里的代码可以被复制到Windows剪切板并且粘贴到 


代码窗口里去。如果对象浏览器和代码窗口都是可见的,你只要选中代码格式里的文本,直接拖曳 


到代码窗口就行了。 


通过对象浏览器窗口上的横竖分割线,你可以轻易地改变各个窗口的大小。 


你已经发现了对象浏览器,你也许在想你如何才能让它帮助你进行VBA编程。假设你在工作表中央 


放置了一个文本框,你如何让Excel将这个文本框移动到工作表的左上方? 


1. 打开一个新工作表 


2. 选择“视图”-“工具栏”,然后点击“绘图” 


3. 点击“绘图”上的文本框,在工作表中央画一个文本框,并且随便输入什么文字 


4. 选择文本框之外的任意单元格 


5. 按下Alt+F11激活VB编辑器窗口,并且选择工程浏览器窗口的Personal (Personal.xls) 


6. 选择“插入”-“模块”,增加一个新的模块 


7. 在属性窗口,给该模块重命名:Manipulations 


8. 选择“视图”-“对象浏览器”,或按F2 


9. 在“工程/库”下拉列表框里选择“Excel”类 


10. 在搜索框里输入“textbox”并点击搜索按钮。确保你没有在文字间敲入空格。 






                                    55 




----------------------- Page 72-----------------------


图2-18 Excel 在工作表上面的名称框里显示插入的对象名称 






图2-19 使用对象浏览器窗口,你可以找到合适的VBA指令来编写你自己的过程 


显示的结果表明对象Shapes掌管我们文本框操作(参见图2-19)。从成员列表清单上看,你可以很 


快就知道AddTextbox方法就是用来在工作表里添加文本框的方法。代码格式窗口显示了使用该方法 


的正确语法。如果你选择AddTextbox方法并且按F1,你将看到关于它的帮助窗口,有更详细的关于 


如果使用该方法的信息(参见图2-20) 






                                   56 




----------------------- Page 73-----------------------


图2-20 要获取对象浏览器找到的任何项目详细信息,只要选择整个项目并且按F1就可以了 


当你细看AddTextbox方法的自变量和它们在帮助窗口上的解释时,你就可以很快地知道文本框在工 


作表中的位置是由Left和Top属性来决定的。你需要做的只是返回代码窗口,编写指令来移动文本 


框到工作表的左上方。 


11. 关闭对象浏览器和帮助窗口(如果它们还是打开的) 


12. 双击Manipulations模块,输入过程MoveTextBox: 


Sub MoveTextBox() 


      With ActiveSheet.Shapes("Text box 1")  ‘Text box 1在中文版本里为“文本框 


1” 


            .Select 


            .Left = 0 


            .Top = 0 


      End With 


End Sub 


13. 选择“运行”-“运行宏”来测试这个过程 


当你返回到 放置该文本 框的工作表 时,该文本 框已经移动 到了工作表 的左上方了 。注意, 


MoveTextBox程序在Shapes集合里选择了“Text box 1”。Text box 1是工作表里第一个对象的默认 


名称。你每次增加新的对象后,Excel将给它安排新的好码(编号)。除了使用对象名称外,你还可 


以引用集合成员的编号。例如,你可以输入: 


With ActiveSheet.Shapes(1) 


来代替: 






With ActiveSheet.Shapes("Text box 1") 


我们来用VB操纵另一个对象,你自己试试。在你放置文本框的工作表里再放置一个小圆圈。使用绘 


图工具上的椭圆工具画这个圆圈。在Manipulations模块里插入一个新的过程,并且编写代码来放 


置圆圈。记住,Excel连续地编号。第一个对象的编号为1,第二个则为2,等等,不管这个对象的 


类型是文本框,椭圆或者是矩形,没有关系。 


下面的过程MoveCircle演示如何将当前工作表里的椭圆移动到左上方去: 






                                    57 




----------------------- Page 74-----------------------


Sub MoveCircle() 


      With ActiveSheet.Shapes(2) 


            .Select 


            .Left = 0 


            .Top = 0 


      End With 


End Sub 


移动椭圆和移动文本框或者放在工作表里的其它对象类似。注意,过程中引用的是对象的编号,而 


非它的名称椭圆 2。当你运行MoveCircle时,Excel移动的是椭圆,而不是文本框了。 






20 使用 VBA 对象库 






在前面的例子里,你学习使用了Excel对象库里的Shapes(图形)集合成员的属性。Excel库包含专 






门使用Excel的对象,而VBA库则提供对许多内置VBA函数的访问,这些函数按类别分组。这些函数 


是通用的,它们使你能够管理文件,设置日期和时间,与用户交流,转换数据类型,处理文本串或 


者进行数学计算。在下面的练习中,你将学习如何使用内置的VBA函数来创建一个新文件夹,而不 


需要离开Excel界面: 


1. 回到模块Manipulations,那里有你的MoveTextBox和MoveCircle过程 


2. 输入一个新的过程: 


   Sub NewFolder() 


3. 点击回车键,VB会自动输入结束关键词End Sub 


4. 按下F2激活对象浏览器 


5. 在“工程/库”列表框里选择VBA 


6. 在搜索文本框里输入file并且回车 


7. 滚动成员列表框,并且选中MkDir方法(参见图2-21) 


8. 点击对象浏览器上的“复制”按钮,将被选择的方法名称复制到剪贴板 






图2-21 编写过程时,向对象浏览器寻求帮助来找内置的VBA函数 


9. 返回Manipulations窗口,并且将复制的指令粘贴到NewFolder过程 


10. 输入一个空格,接着是”C:\Study”。确保你在引号里输入了整个路径名。NewFolder过程为: 


   Sub NewFolder() 


      MkDir "C:\Study" 






                                    58 




----------------------- Page 75-----------------------


   End Sub 


11. 运行过程NewFolder 


当你运行NewFolder过程,VB在C盘上创建了一个新的文件夹。激活Windows浏览器可以查看该新文 


件夹。创建一个新的文件夹后,你可能会发现你根本就不需要它,虽然你可以轻易地从Windows浏 


览器里删除该文件夹,但是,如何从编程上去掉它呢?对象浏览器上列出了许多对文件夹和文件操 


作很有帮助的其它方法。RmDir方法正如MkDir 方法一样使用简单。想要删除你硬盘上的“Study” 


文件夹,只要将MkDir方法换成RmDir方法然后重新运行NewFolder过程就可以了。或者,你也可以 


创建一个新的过程RemoveFolder,如下: 


      Sub RemoveFolder() 


            RmDir "C:\Study" 


      End Sub 


RmDir方法允许你从硬盘上删除不需要的文件夹。 






21 用对象浏览器来定位过程 






除了定位对象,属性和方法外,对象浏览器还是个定位在不同工程里面的过程非常方便的工具。下 


面的例子给你演示如何查看存在“Personal”工作簿里面的过程: 


1. 激活对象浏览器并且选择工程/库下拉列表里的Personal。(译者:因为我没有Personal这个文 


   件。。。) 






图2-22 对象浏览器列出所有在某个特定VBA工程里可用的过程 


对象浏览器的左边显示所选工程里面对象名称,而右边则列出了所有可用的过程。 


2. 双击NewFolder过程名称,VB将光标定位到该过程的第一行 


3. 关闭对象浏览器 






22 使用立即窗口 






在你开始创建一个完善的VBA过程前(在下一章),先来做一些热身练习,增加你的VBA词汇。你怎 


样才能学得快而且没有痛苦?你如何试验一下一些新学的VBA指令?这里有一些简短的,互动的语 


言练习:输入一个简单的VBA指令,Excel会检查并且将结果显示在下一行。我们开始来设定你的练 


习屏幕: 


1. 在VB编辑器窗口,选择“视图”-“立即窗口” 


在决定使用在你自己的VBA过程之前,立即窗口可以用来试验VB语言中不同的指令,函数和运算符。 


这是一个非常好的调试新语言的工具,你输入在这个窗口里面的指令,将会立即显示结果。 


立即窗口可以在VB编辑器窗口上任意移动,也可以设置为可连接的,这样它就会出现在相同的地方。 


可以通过选项对话框上的“可连接的”页来打开或关闭可连接设置。在VB编辑器窗口上按下Ctrl+G 


就可以快速访问立即窗口。立即窗口允许你输入VBA语句,并且测试它们的结果,而不需要写成一 


个过程。立即窗口就像一个草稿板,你可以用它测试你的语句。如果该语句输出了你希望的结果, 


你就可以将立即窗口上的语句复制到你的过程中去(或者,你也可以将语句拖曳到代码窗口,如果 


代码窗口是可见的) 


                                    59 




----------------------- Page 76-----------------------


2. 将Excel和VB编辑器窗口并排排列 


3. 在立即窗口里输入下述指令,并且回车 


   Worksheets("Sheet2").Activate 


当你按下回车键,VB开始工作,如果你上面输入的语句是正确的话,VBA激活当前工作簿里的第二 


个工作表。工作簿底部的Sheet2这时应该是突出显示的。 


4. 在立即窗口,输入其它VBA语句并回车 


   Range("A1:A4").Select 


你一旦按下回车,VB将选中当前工作表的A1,A2,A3和A4 


5. 在立即窗口里输入下述指令: 


   [A1:A4].Value = 55 


当你按下回车,VB在A1:A4中的每个单元格里放置数字55。上面的语句是引用Range对象的一种所写 


方式,完整的语法可读性更强: 


   Range("A1:A4").Value = 55 






图2-23 将Excel和VB窗口并排排列让你可以观察指令的运行 


6. 在立即窗口输入下述指令: 


   Selection.ClearContents 


回车后,VBA清除所选单元格区域的内容,区域A1:A4现在是空的 


7. 在立即窗口输入下述指令: 


   ActiveCell.Select 


回车后,VB激活A1单元格 






图2-24 在立即窗口里输入指令,一旦你按下回车键,指令就会被执行 






                                    60 




----------------------- Page 77-----------------------


图2-24显示了上面练习中在立即窗口里输入的所有指令。你每次按下回车键后,Excel总是执行光 


标所在行的语句。如果你想要再次执行同一指令,那么点击该指令行的任意位置,回车。为了更多 


的练习,重新运行图2-24里语句,从立即窗口的第二行指令开始,点击合适的地方并回车,一个 


一个地执行这些指令。 






23 获取立即窗口里的信息 






到目前为止,你已经使用立即窗口执行操作了,这些操作也可以是手动地在工作表的任意区域点击 






鼠标并且输入数据。立即窗口也允许你问问题。假设你想要找到下面问题的答案:“现在选中的是 


哪些单元格?”,“当前单元格里的值是多少?”,“当前工作表的名称是什么?”,“当前窗口的编号 


是多少?”使用立即窗口,你可以轻易地找到这些问题,以及其它问题的答案。在前面的例子里, 


你输入了好几个指令,让我们返回立即窗口去问几个问题。Excel甚至在你关闭了立即窗口后还能 


记住你在立即窗口里输入的指令。当你退出Excel时,立即窗口的内容自动会被删除。 


1. 鼠标点击立即窗口第二行你输入Range("A1:A4").Select的任意地方 


2. 回车,让Excel再次选择单元格A1:A4 


3. 在立即窗口新的一行输入下面的问题: 


   ?Selection.Address 


当你按回车,Excel不会选择工作表的任何东西,取而代之,立即窗口上会在另外一行显示该指令 


的结果。在该例中,Excel返回的是当前被选择的单元格的绝对地址($A$1:$A$4)。问号(?)告诉 


Excel在立即窗口显示指令的结果。除了问号,你还可以使用Print关键字。让我们使用关键字Print 


问工作表名称 


4. 在立即窗口新的一行,输入下述问题: 


   Print ActiveWorkbook.Name 


回车后,Excel在立即窗口新的一行输入了当前工作簿的名称。 


找找应用程序的名称如何?Chap02.xls的父对象是谁? 


5. 在立即窗口新的一行,输入下述问题: 


   ?Application.Name 


Excel会显示它自己的全名:Microsoft Excel 


立即窗口也可以用来做一个快速计算 


6. 在立即窗口新的一行,输入下述问题: 


   ?12/3 


回车后,Excel会在下一行显示该除法运算的结果。但是,万一你想立即知道3+2和12*8的结果呢? 


你可以将它们输入在一行,而不必分成两行,例如: 


   ?3+2:?12*8 


注意,冒号将两个代码块分割开来。 


当你按下回车键,Excel分别在立即窗口的两行显示结果5,96。 


下面是你在立即窗口里输入的所有指令,以及Excel对你问题的回答: 


   Worksheets("Sheet2").Activate 


   Range("A1:A4").Select 


   [A1:A4].Value = 55 


   Selection.ClearContents 


   ActiveCell.Select 


   ?Selection.Address 


   $A$1:$A$4 


   Print ActiveWorkbook.Name 


   Chap02.xls 


   ?Application.Name 


   Microsoft Excel 


   ?12/3 


   4 


   ?3+2:?12*8 






                                   61 




----------------------- Page 78-----------------------


   5 


   96 


要清除立即窗口里的指令,只要选中所有指令并且按下Delete键 






24 学习对象 






要在Excel里创建一些自定义应用程序,需要一些常用对象或者对象集合的工作知识,例如Range, 


Workbook (Workbooks),Worksheet (Worksheets),Window (Windows)和 Application。在前面部 


分,你开拓了学习VB的许多方法。这里有一个总结关于什么时候使用什么工具: 


  当你在一个现行VBA过程,对对象,属性或方法有疑义时按F1打开在线帮助 


  如果你需要快速列出每个可用对象的属性和方法时,或者查找一个很难找到的过程时,使用对 


   象浏览器 


  如果你想要测试VBA并且立即查看VBA命令的结果时,激活立即窗口。 


本章剩余的几页里有一些VBA语言训练,可以帮助你更好地理解VBA语法。如果你花些时间在立即窗 


口过一遍这些语法训练,你将理解绝大部分。 






图2-25 Excel对象模型里的Range对象 






25 电子表格单元格操作 






当你已经准备好编写你自己的VBA过程,将电子表格任务自动化的时候,你很可能是从寻求操作电 


子表格单元格的指令开始的。你需要知道如何选择单元格,如果在单元格输入数据,如何给单元格 


区域命名,如何设置单元格格式,以及如何移动,复制和删除单元格。虽然这些任务可以通过鼠标 


或键盘轻易执行,掌握VBA这些方面的技术需要一些练习。你必须使用Range对象来引用单个单元格, 


单元格区域,行或列。如果你看了Excel对象模型,你会注意到Range对象是另外一个大对象—— 


Worksheet对象——的一部分。有三种属性让你访问Range对象:Range属性,Cells属性和Offset 


属性。 






26 使用 Range 属性 






Range属性返回一个单元格或者单元格区域。引用必须是A1在引号里的样式(例如:”A1”)引用 


可以包括区域运算符冒号(例如:”A1:B2”)或者联合运算符逗号(例如:”A”,”B12”) 


VBA操作                              立即窗口输入 


选择单个单元格(例如A5)                      Range("A5").Select 


选择一个单元格区域(例如A6:A10)                Range("A6:A10").Select 


选择一些不相邻的单元格(例如A1, B6, C8) Range("A1, B6, C8").Select 


选择一些不相邻的单元格和单元格区域(例 Range("A11:D11, C12, D3").Select 


如 


A11:D11, C12, D3) 






27 使用 Cells 属性 






当你要选择一个确定的单元格时,Cells属性要求两个自变量,第一个是行号,第二个是列号或者 


列字母。自变量输入在括号中。如果忽略自变量,Excel将会选择当前工作表的所有单元格。 






                                   62 




----------------------- Page 79-----------------------


VBA操作                               立即窗口输入 


选择单个单元格(例如A5)                       Cells(5, 1).Select或Cells(5, A).Select 


选择一个单元格区域(例如A6:A10)                 Range(Cells(6, 1), Cells(10, 1)).Select 


选择工作表中所有单元格                         Cells.Select 






注意,在上面的例子中,你如何结合使用Range和Cells属性: 






   Range(Cells(6, 1), Cells(10, 1)).Select 






在上面的例子里,第一个Cells属性返回单元格A6,而第二个返回单元格A10。Cells属性返回的单 


元格之后又当做Range对象的参数。结果Excel就选择了上面单元格为第一个Cells属性返回的结果 


和下面为第二个Cells属性返回单元格的区域了。 


工作表是单元格的集合,你也可以使用只带一个自变量的Cells属性来表示单元格在工作表所有单 


元集合中的位置。Excel按下列方式给单元格编号:单元格A1是工作表中的第一个单元格,B1是第 


二个,C1是第三个,等等。Cell256是第一行中的最后一个单元格。你也许会想起Excel只有256列。 


VBA操作                              立即窗口输入 


选择单元格A1                            Cells(1).Select or Cells.Item(1).Select 


选择单元格C1                            Cells(3).Select or Cells.Item(3).Select 


选择单元格IV1                           Cells(256).Select or Cells.Item(256).Select 


选择单元格A2                            Cells(257).Select or Cells.Item(257).Select 






注意,Item是返回一个集合成员的属性。因为Item是一个集合的默认成员,你可以直接引用工作表 


单元格,而不必明确地使用Item属性。 


现在你发现了两种方法选择单元格(Range属性和Cells属性),你也许很迷惑为什么要使用更复杂 


的Cells属性呢?很明显Range属性更具有可读性,毕竟,你远在决定学习VBA之前就在Excel公式和 


函数里面使用了Range引用。然而,当需要将单元格当做集合操作的时候,Cells属性则使用更方便。 


使用这个属性去访问单元格集合中的所有单元格或者单个单元格。 






28 使用 Offset 属性 






另外一个引用工作表单元格非常灵活的方法是使用Offset属性。当工作表任务自动化时,你也许不 


知道某个单元格的确切地址。你如何能够选择一个你根本不知道地址的单元格?你可以让Excel基 


于当前选择的单元格来选择一个位置。Offset属性通过计算从开始选择的单元格向下或向上移动的 


具体行数,来得到新的区域。同样也可以从当前选择的单元格区域向右或向左移动具体的列数。 


Offset属性使用两个自变量来获得新单元格区域的地址。第一个自变量表示行偏移,第二个自变量 


则表示列偏移。我们来测试一下几个例子: 


VBA操作                             立即窗口输入 


选择单元格A1下面一行和右边三列的单元格 Range("A1").Offset(1, 3).Select 


选择单元格D15上面两行和左边一列的单元格Range("D15").Offset(-2, -1).Select 


选择当前单元格上面一行的单元格(同列) ActiveCell.Offset(-1, 0).Select 






上面的第一个例子里,Excel选择的时单元格D2。一旦你输入了第二个例子,Excel选择了单元格C13。 


如果单元格A1和D15已经被选中了,你也可以将上面的两个例子改写为这样: 


   Selection.Offset(1, 3).Select 


   Selection.Offset(-2, -1).Select 


注意,上面第三个例子里的第二个自变量是0,第一个或第二个自变量为0时,Offset属性相应表示 


当前行或当前列。如果当前活动单元格在第一行,那么指令ActiveCell.Offset(-1, 0).Select会 


导致错误。 


当使用Offset属性时,你可能有时需要改变选择区域的大小。假设开始选择的区域是A5:A10,如何 


将选择区域向下移动两行,向右移动两列,然后再改变新选择区域的大小呢?假设新的选择区域应 


该是C7:C8。Offest属性只能完成前面部分,后面部分要求另外一个属性来完成。Excel有个专门的 


Resize属性,你可以结合Offset属性和Resize属性来回到上面的问题。在你结合这两个属性之前, 






                                   63 




----------------------- Page 80-----------------------


我们先来看看如何独立地使用它们: 


1. 将Excel窗口和VB窗口并排显示 


2. 激活立即窗口,并且输入下述指令: 


   Range("A5:A10").Select 


   Selection.Offset(2, 2).Select 


   Selection.Resize(2, 4).Select 


上面的第一条指令选择区域A5:A10,当前活动单元格是A5。第二条指令将选区偏移到C7:C12。单元 


格C7处于活动单元格A5的向下两行和向右两列。现在,活动单元格是C7。最后一条指令将当前选区 


改变大小,单元格区域C7:C8被选中了,而不再是C7:C12。象Offset属性一样,Resize属性也需要 


两 个 自 变 量 。 第 一 个 是 你 要 选 取 的 行 数 , 第 二 个 则 是 要 选 取 的 具 体 列 数 因 此 , 


指 令 


Selection.Resize(2, 4).Select将当前选择区域改为两行和四列 


后面两行指令可以结合成下面方式: 


   Selection.Offset(2, 2).Resize(2, 4).Select 


上面的例子,先是Offset属性计算得到新区域的起始点(译者:选区左上角的单元格),接着是Resize 


属性决定新选区的大小,然后是Select方法选取具体的单元格区域。 


技巧2-6:录制单元格的选择 


宏录制器默认地使用Range属性录制选择单元格。如果你打开宏录制器,并且选择单元格A2,输入 


“text”,再选择单元格A5,你将在VB编辑器窗口里得到下述代码: 


Range("A2").Select 


ActiveCell.FormulaR1C1 = "text" 


Range("A5").Select 


如果你使用相对引用方式,宏录制器会使用Offset属性。你可以在录制前,点击宏录制工具条上的 


相对引用按钮。宏录制器将得到如下代码: 






ActiveCell.Offset(-3, 0).Range("A1").Select 


ActiveCell.FormulaR1C1 = "text" 






ActiveCell.Offset(3, 0).Range("A1").Select 


当你使用相对引用方式录制宏时,过程总是会选择相对于当前活动单元格的单元格。注意,上面指 


令中的第一和第三行的引用单元格A1,即使我们没有涉及到A1的任何东西。你可能记得,在第一章 


中,宏录制器用它自己的方式将事情搞定。为了将上面的指令变简单一些,你可以删除对单元格A1 


的引用: 


ActiveCell.Offset(-3, 0).Select 


ActiveCell.FormulaR1C1 = "text" 


ActiveCell.Offset(3, 0).Select 


使用相对引用来录制过程后,不要忘记再次点击这个按钮,如果下次录制一个非相对地址的过程。 






29 选择单元格的其它方法 






如果你经常需要访问你工作表里某些遥远的单元格,你可能已经对下面的键盘快捷键很熟悉:End+ 


上箭头, End+下箭头, End+左箭头和End+右箭头。在VBA中,你可以使用End属性快速地移动到遥 


远的单元格。 


VBA操作                            立即窗口输入 


选择任何行的最后一个单元格                    ActiveCell.End(xlright).Select 


选择任何列的最后单元格                      ActiveCell.End(xldown).Select 


选择任何行的第一个单元格                     ActiveCell.End(xleft).Select 


选择任何列的第一个单元格                     ActiveCell.End(xlup).Select 






注意,End属性要求一个自变量来表示你要移动的方向。使用下列Excel内置的常数来跳到具体的方 


向:xlright, xlleft, xlup, xldown。 






30 选择行和列 






Excel使用EntireRow和EntireColumn属性来选择整行或整列。 






                                   64 




----------------------- Page 81-----------------------


VBA操作                             立即窗口输入 


选择当前活动单元格所在行的整行                   Selection.EntireRow.Select 


选择当前活动单元格所在列的整列                   Selection.EntireColumn.Select 






你选择了一个单元格区域,你也许想要知道选区包括多少行,多少列。我们来让Excel计算区域 


A1:D15中的行数和列数: 


1. 在立即窗口里输入下述VBA语句 


   Range("A1:D15").Select 


如果Excel窗口可见,当你按回车后,VBA会选中区域A1:D15 


2. 输入下列语句来得到选区的行数 


   ?Selection.Rows.Count 


一旦你回车,VBA在下一行显示结果。你的选择包括15行 


3. 输入下列语句来得到选区的列数 


   ?Selection.Columns.Count 


现在VBA告诉你,选中的区域A1:D15占据了四列的宽度。 


4. 将光标放在关键字Rows或Columns中的任意位置,并且按下F1,获取这些有用属性的更多信息。 






31 获取工作表信息 






Excel工作表有多大?它有多少单元格,列和行?即使你忘记了这些细节,使用Count属性。 


VBA操作                                立即窗口输入 


计算Excel工作表里总单元格数                     ?Cells.Count 


计算Excel工作表里总行数                      ?Rows.Count 


计算Excel工作表里总列数                       ?Columns.Count 






 Excel 2002工作表里有16,777216个单元格,65,536行和256列。 






32 往工作表输入数据 






输入工作表里的信息可以是文本,数字或者公式。你可以使用Range对象的两种属性之一来往单元 


格或单元格区域里输入数据:Value属性或者Formula属性。 


Value属性: 


   ActiveSheet.Range("A1:C4").Value = "=4 * 25" 






Formula属性: 


   ActiveSheet.Range("A1:C4").Formula = "=4 * 25" 






上面两种例子,A1单元格都显示4乘25的结果100。 


VBA操作                               立即窗口输入 


在单元格A5里输入文本“Amount Due”             Range("A5").Formula = "Amount Due" 


在单元格D21里输入数字“123”                   Range("D21").Formula = 123 


                                    Range("D21").Value = 123 


在单元格B4里输入公式“=D21*3”                 Range("B4").Formula = "=D21 * 3" 






33 返回工作表中的信息 






毫无疑问,你在某些VB过程中可能需要返回单元格或者单元格区域的内容。虽然你既可以使用Value 


属性也可以使用Formula属性,但是,这次,Range对象的这两个属性是不可互用的。 


  Value属性显示具体单元格中公式的结果。例如,如果A1中含有公式“=4*25 ”,那么指 


   令?Range("A1").Value将会返回值100 


  如果你想要显示公式,而不是结果,那么你必须使用Formula属性:?Range("A1").Formula。 


   Excel将会显示公式“=4*25”而不是结果100 






                                    65 




----------------------- Page 82-----------------------


34 单元格格式 






一个频繁的任务就是给选中的单元格或区域设置格式。你的VBA过程可能需要查明某个具体单元格 


的格式。我们可以使用NumberFormat属性来找回单元格格式: 


   ?Range("A1").NumberFormat 


在立即窗口输入上面的问题后,Excel显示“General”(译者:中文版本是“常规”,G/通用格式), 


它表示所选的单元格没有设置任何特殊的格式。要用VBA改变单元格格式,输入下列指令: 


   Range("A1").NumberFormat = "$#,##0.00" 






如果你在单元格A1里输入125,当你使用上面的指令给它设置格式后,单元格A1将显示“$125.00”。 


你可以在Excel窗口的“设置单元格格式”对话框里查找必要的格式代码(“格式”-“单元格”)。 


如果你要的格式没有列在“设置单元格格式”对话框里,那么请参考在线帮助,查找创建用户定义 


的格式指导。 






图2-26 你可以使用设置单元格格式对话框里的自定义给选择的单元格或单元格区域设置不同的 


格式 






35 移动,复制和删除单元格 






在你做一个新的工作表模板时,你会发现经常要移动,复制和删除单元格内容。VB让你的工作表编 


辑工作自动化变得可能,只要使用一些容易使用的方法就行:Cut,,Copy和 Clear。 


VBA操作                             立即窗口输入 


移动单元格A5的内容到单元格A4里面                Range("A5").Cut 


                                  Destination:=Range("A4") 


复制单元格A3里的公式到区域D5:F5中              Range("A3").Copy 


                                  Destination:=Range("D5:F5") 


清除单元格A4里的内容                       Range("A4").Clear 


                                  Range("A4").Cut 






注意,使用在Range对象上的Cut和Copy方法都需要一个叫“Destination”的特殊自变量。这个自 


变量明确你要放置剪切或复制的数据的单元格或单元格区域地址。在最后一个例子中,使用了没有 


Destination自变量的Cut方法来去除具体单元格的数据。Clear方法将删除具体单元格或单元格区 


域的所有内容,包括格式和批注。如果你想要明确你要删除什么,使用下列方法: 


  ClearContents-仅清除单元格或单元格区域内的数据 






                                  66 




----------------------- Page 83-----------------------


  ClearFormats-仅清除格式 


  ClearContents-清除区域里的所有批注  ??注:ClearComment 






36 操作工作簿和工作表 






既然你已经涉足操作工作表单元格和单元格区域,是时候上一个台阶,学习如何控制单个工作簿, 


已经整个工作簿集合了。如果你不知道如何打开一个新工作簿的话,你就不知道准备一个新的电子 


表格了;如果你不知道如何关闭工作簿,你就不知道如何将工作簿从屏幕上消除。这些重要的任务 


由两个VBA方法处理:Add和Close。下面的练习将给你必要的如何操作工作簿和工作表的语言技巧。 


VBA操作                             立即窗口输入 


打开一个新工作簿                          Workbooks.Add 


获得第一个工作簿的名称                       ?Workbooks(1).Name 


获得打开的工作簿数目                        ?Workbooks.Count 


激活第二个打开的工作簿                       Workbooks(2).Activate 


激活工作簿Chap02.xls                   Workbooks("Chap02.xls").Activate 


当前活动的工作簿存盘为NewChap.xls            ActiveWorkbook.SaveAs Filename:="NewChap.xls" 


关闭第一个工作簿                          Workbooks(1).Close 


关闭当前活动的工作簿,不保存变化                  ActiveWorkbook.Close SaveChanges:=False 


关闭所有打开的工作簿                        Workbooks.Close 






如果你运行了最后一个例子,那么现在你所有的工作簿都已经关闭了。在你要在工作表上使用前, 


请确保先打开一个新工作簿。当你除了单个工作表时,你必须知道如何在工作簿里添加新的工作表, 


知道如何选择一个或一组工作表,知道如何命名、复制、移动和删除工作表。在VB里,每个任务都 


需要一个专门的方法或属性。 


VBA操作                             立即窗口输入 


添加一个新工作表                          Worksheets.Add 


获得第一个工作表的名称                       ?Worksheets(1).Name 


选择名为“Sheet3”的工作表                  Worksheets(3).Select 


选择第一,第三和第四个工作表                    Worksheets(Array(1,3,4)).Select 


激活名为“Sheet1”的工作表                  Worksheets(“Sheet1”).Activate 


将工作表“Sheet2”移动到工作表“Sheet1”Worksheets("Sheet2").Move 


之前                                Before:=Worksheets("Sheet1") 


重命名工作表“Sheet2”为“Expenses” Worksheets("Sheet2").Name = "Expenses" 


获得当前工作簿里的工作表数目                    ?Worksheets.Count 


删除当前工作簿里的工作表“Expenses”            Worksheets("Expenses").Delete 






注意Select方法和Activate方法之间的区 






别: 


  当只要一个工作表被选择时,Select和Activate方法可以互换使用 


  如果你要选择一组工作表,Activate方法将让你决定你选中的工作表中哪个要激活。我们知道, 


   同时只能有一个工作表被激活。 


技巧2-7:Sheets(译者简称为“表”)而不是Worksheets(译者简称为“工作表”) 


除了工作表之外,工作簿集合里还包括图表。使用Add方法在工作簿里添加一个新图表: 


Charts.Add 


统计图表数目,使用: 


?Charts.Count 


在Excel 97之前的版本中,工作簿集合里包括两种额外的表:DialogSheets和Modules。Dialogs 


已经被更亲切的用户窗体(UserForms)所取代了。从Excel 97开始,对话框和模块都被创建在VB 


编辑器窗口里面了。 






37 操作窗口(Windows) 






当在好几个Excel工作簿上工作,并且需要比较或者巩固数据,或当你想要看同一个工作表里的不 






                                   67 




----------------------- Page 84-----------------------


同部分时,你很可能要用到Excel“窗口”菜单里的选项:新建窗口和重排窗口。我们来看看如何 


通过VBA来安排窗口。 


VBA操作                              立即窗口输入 


在新窗口里显示当前活动工作簿                     ActiveWorkbook.NewWindow 


在屏幕上显示所有打开了的工作簿                    Windows.Arrange 


激活第二个窗口                            Windows(2).Activate 


获得当前窗口的名称                          ?ActiveWindow.Caption 


将当前窗口的名称改为“My Window”              ActiveWindow.Caption = "My Window" 






当你在屏幕上显示窗口时,你可以决定如何排列它们。Arrange方法有许多自变量,让你如何放置 


窗口的自变量称为ArrangeStyle(排列方式)。如果你忽略ArrangeStyle自变量,Excel将平铺所有 


窗口。 






常数                          值                  描述 


xlArrangeStyleTiled         1                  平铺窗口(默认模式) 


xlArrangeStyleCascade       7                  层叠窗口 


xlArrangeStyleHorizontal    2                  水平并排窗口 


xlArrangeStyleVertical      3                  垂直并排窗口 






除了使用常数名称外,你也可以使用上面列出的等价值。要将所有窗口层叠起来,写下面的指令就 


可: 


   Windows.Arrange ArrangeStyle:=xlArrangeStyleCascade 






或者更简单点: 


   Windows.Arrange ArrangeStyle:=7 






38 管理 Excel 应用程序 






在本章的开始部分,你学习了对象是组织在一个叫对象模型的专门结构。在应用程序的对象模型的 






最上面就是应用程序它本身。通过控制Application对象,你可以进行很多操作,例如将屏幕显示 


效果保存为当日最后显示的效果,或者退出该应用程序。你知道,Excel允许你使用“文件”菜单 


里的选项“保存工作区”来保存屏幕设定。在VBA里可以很容易地完成保存工作区的工作: 


   Application.SaveWorkspace "Project" 


上面的指令将屏幕设置保存在名叫“Project”的工作区里。下次你要在相同的文件和窗口排列时, 


只要打开“Project”文件,Excel就会打开正确的文件和恢复你要的屏幕。 


VBA操作                              立即窗口输入 


获取当前应用程序名称                         ?Application.Name 


将Excel应用程序标题改为“My Application” Application.Caption = "My Application" 


将 Excel 应 用 程 序 标 题 改 回 为 “ Microsoft           Application.Caption = "Microsoft Excel" 


Excel” 


获取你正在使用的操作系统                       ?Application.OperatingSystem 


获取该应用程序注册的人名或公司名                   ?Application.OrganizationName 


获取Excel.exe保存的文件夹路径                ?Application.Path 


退出Excel                            Application.Quit 






39 接下来…… 






在本章,你学习了很多基础的VBA术语和内置工具,可以用来使你的程序编写和调试更容易。你现 






在应该对绝大多数Excel对象是如何组织和控制的有了一个比较好的了解。我努力使描述尽量少, 


并且注重于教你如何使用你的新语言技巧立即控制Excel而不必先编写过程。正因为此,我注重于 


立即窗口。VB过程通常包含多于一行的代码,事实上,它们可能变得很复杂。在你开始创建完整的 


VBA过程之前,你仍然需要学习一些事情。例如,你如何保存目前Excel返回的信息,你的过程稍后 






                                   68 




----------------------- Page 85-----------------------


可以使用?在立即窗口里输入指令的时候,你学习了如何问Excel一些重要的信息,你得到了类似 


“当前活动工作簿里有多少工作表?”或“单元格A4的内容是什么?”问题的答案。Excel不会在 


乎你的问题有多么烦,只要你输入符合严格VBA语法的问题,Excel就会给你答案。当你开始编写你 


自己的过程时,你会需要知道如何保存Excel的答案。在下章里,你将学习如何保存这种以后变量 


需要用到的信息。你也将会展开数据类型和常数主题的学习。 






                       第三章 了解变量,数据类型和常量 






作者:Julitta Korol  翻译:Tiger Chen Dec 18’ 2004 


就象现实生活中一样,编程中也是有些事情必须马上做,而其它的事情可以稍后进行。当你推迟一 


件事情,你可以将它放入你心里的或纸上的“要做的事情”清单。清单上零零散散的事情,经常按 


照它们类型或者重要性来分类。当你将任务交给别人或者最终你要开始做了,你需要将该任务从清 


单里划掉。本章将演示你的VBA过程如何记住一些重要的信息,后面将用在你的语句或计算里。你 


将学习过程如何保留不断地往变量输入“要做的事情”,如何声明变量,以及它们和数据类型及常 


量有何关系。 






1 保存 VBA 语句的结果 






在第二章,你在立即窗口上输入一些VB指令,并且返回一些信息。例如,当你输入?Cells.Count, 


你发现工作表里有16,777,216个单元格。然而,当你在立即窗口之外的地方写VB过程时,你不能使 


用问号。当你忽略问号输入Cells.Count,VB不会突然停下来告诉你这个指令的结果。如果你想要 


知道某个指令执行后的结果,你就必须告诉VB记住它。在编程中,VB指令返回的结果可以赋值给变 


量。 






2 变量是什么 






变量是一个简单的用来引用一条数据的名称。你每次想要记住一个VBA指令的结果时,考虑用一个 


名称来代表它。例如,如果你必须用数字16,777,216来提醒你工作表中的总单元格数目,你可以使 


用一个名称,如AllCells,NumOfCells,TotalCells,等等来代替。变量名称里可以包含字母,数 


字和一些标点符号,除了下面这些之外, # $ % & @ ! 


变量的名称不可以以数字开始,也不可以含有空格。如果你想在变量名称里包含多于一个词语,可 


以使用下划线。虽然变量名称最多可以包含254个字母,但是,你最好使用短而简单的变量名称。 


使用短名称将会节省你的输入时间,如果你需要在你的VB过程里多次引用该变量的话。VB不管你在 


变量名称里使用大写字母还是小写字母,然而,大多数编程者使用小写字母,并且当变量名称包括 


一个或多个词语时,他们使用标题字母,那就是,象下面这样,他们将每个词语词头大写: 


NumOfCells,First_Name。(译者:中文也可以做为变量名称使用,但是,个人不建议使用中文) 


技巧3-1 不能用作变量名称的词语 


除了这些VBA占用了的词语之外,你可以使用任何你想用的标签作为变量名称。在VBA中有特定意义 


的VB语句以及其它某些词语不能用作变量名称。例如,词语Name,Len,Empty,Local, Currency 


或者Exit,如果你使用它们作为变量名,将会产生错误。 


技巧3-2 富有意义的变量名称 


给变量那种可以帮助你记住它们作用的名称。有些程序员使用前缀来识别变量类型。在你的代码中, 


一个以前缀“str”开头的变量名称(例如strName),很快就可以知道它是传递文本字符串的变量。 






3 数据类型 






当你创建VB过程时,你脑海里必然有个目的,你想要处理数据。因为你的过程要处理不同类型的信 


息,所以,你应该了解VB如何储存数据。“数据类型”这个术语决定了数据如何储存在电脑的内存 


里。例如,数据可以储存为数字,文本,日期,对象,等等。如果你忘了告诉VB你的数据类型,VB 


将分配数据类型为“Variant”。“Variant”类型有能力解决数据本身的操作类型并且使用该类型。 


表3-1里列出了VB数据类型。除了内置的数据类型之外,你还可以定义你自己的数据类型。(你将 


在第八章里看到用户自定义的数据类型的例子。)因为不同的数据类型占据电脑内存的空间是不一 


样的,一些类型比另外一些更“贵”些,因此,为了保存内存并确保你的过程运行更快,你应该选 


择占用字节最少的,同时又能够处理你数据的数据类型。 


表3-1 VBA数据类型 






                                   69 




----------------------- Page 86-----------------------


数据类型(名称)          大小(字节) 描述 


Boolean           2          逻辑值True或False 


Byte              1          0到255的整数 


Integer           2          –32,768到32,767的整数 


Long              4          –2,147,483,648到2,147,483,647的整数 


Single            4          单精度浮点数值 


                             负数:–3.402823E38到–1.401298E–45 


                             正数:1.401298E–45到3.402823E38 


Double            8          双精度浮点数值 


                             负     数     :     –1.79769313486231E308  到 


                             –4.94065645841247E–324 


                             正数:4.94065645841247E–324到1.79769313486231E308 


Currency          8          (放大的整数(译者:整数除以10000得到的数值,参见VBA 


                             帮助))使用在定点计算中: 


                             –922,337,203,685,477.5808                到 


                             922,337,203,685,477.5807 


Decimal           14         +/–79,228,162,514,264,337,593,543,950,335 没 有 小 数 


                             点; 


                             +/–7.9228162514264337593543950335小数点后有28位数 


                             字; 


                             最小的非0数字是 


                             +/–0.0000000000000000000000000001 


Date              8          从100年1月1日到9999年12月31日的日期 


String(变长字符串) 10 字 节 + 变长字符串最多可包含大约 20 亿 ( 2^31)个字符。 


字 


                  符串长度 


String(定长字符串) 字符串长度 定长字符串最多可包含大约65,400 个字符。 


Object            4          对象变量用来引用Excel中的任何对象 


Variant(带数字)  16             最高范围到Double类型的任何数值 


Variant(带字母)      22 字 节 + 和变长字符串的范围一样 


                  字 


用户定义类型            符串长度       每个成员的范围和它的数据类型的范围一致 


(使用Type)          成 员 所 需 


                  的 


                  数值 


4 如何产生变量 






你可以通过一个专门的命令来声明变量从而产生一个变量,或者也可以直接在语句里使用变量(而 


不需要声明)。当你声明变量时,你实际上让VB知道该变量的名称和数据类型,这叫做“强制显式 


声明变量”。 


如果你在使用变量前不告诉VB关于该变量的任何信息,你这是在含蓄地告诉VBA你想要创建这个变 


量。没有明确声明的变量会自动地分配为Variant数据类型(参见表3-1)。虽然不声明变量很方便 


(你可以随意创建变量,并且不用事先知道被赋值的数值的数据类型就可以赋值给该变量),但是, 


它会导致很多问题,参见技巧3-4中要点。 


技巧3-3 强制显式声明变量的好处 


  强制显式声明变量加速过程的执行。因为VB知道数据类型,它只会占用实际储存数据需要的内 


   存 


  强制显式声明变量使你的代码可读性和可理解性增加,因为所有的变量都已列在过程的最前面 


  强制显式声明变量帮助预防由于变量名称拼写错误而导致的错误。VB根据变量声明里的拼写自 


   动更正变量名称。 


技巧3-4 隐式声明变量的坏处 


  如果你错误拼写了一个变量名称,VB会显示运行时间错误,或者产生一个新的变量。你保证需 






                                   70 




----------------------- Page 87-----------------------


   要浪费很多时间来做故障排除,然而,如果在过程前声明了变量,这些很容易避免 


  因为VB不知道你要保存的变量的数据类型,它将分配给它Variant数据类型。这导致你的过程 


   运行要慢一些,因为VB每次在处理这个变量时不得不检查数据类型。因为Variant可以储存任 


   何一种数据类型,VB不得不占用更多的内存来储存你的数据 






5 如何声明变量 






你可以使用关键字Dim来声明变量,Dim代表“Dimension”。关键字Dim后面紧跟变量名称,再后面 


就是数据类型。假设你想让过程显示员工的年龄,你计算年龄之前,必须给过程提供员工的生日。 


你可以这样做,声明一个叫DateOfBirth的变量: 


Dim DateOfBirth As Date 


注意,关键字Dim之后是变量名称(DateOfBirth)。如果你不喜欢这个名称,你可以自由地改为其 


它的,只有你想用的名称不是VBA关键字之一就行。关键字As以及后面的表3-1其中的一个数据类 


型,明确了该变量的数据类型。数据类型Date告诉VB变量DateOfBirth将会储存日期。 


要储存员工的年龄,按下面方式声明变量Age: 


Dim Age As Integer 


变量Age将会储存今天和该员工生日之间年数的数字。因为年龄显示为整年,所以变量Age就被分配 


为Integer数据类型。 


你可能还想要你的程序追踪员工的姓名,因此需要声明另一个变量来保存员工的名和姓: 


Dim FullName As String 


因为词语“Name”已经在VBA占用的清单上,在你的VBA程序里使用它的话保证会有错误。将变量命 


名为FullName并且将它声明为String类型(因为员工姓名是文本),来保存员工姓名。 


技巧3-5 隐式声明变量 


没有用Dim语句来明确声明的变量叫做隐式声明。这些变量自动会被分配一个数据类型Variant。它 


们可以保存数字,字符串和其它信息类型。你可以通过在你VBA程序的任何地方,简单地赋值给一 


个变量名称来创建一个变量。例如,你可以按下述方式来隐式声明变量:DaysLeft = 100 


声明变量被认为是编程的好习惯,因为它使程序可读性增强并且帮助避免某些类型的错误。既然你 


已经知道了如何声明变量,我们就来看一下使用它的一个程序: 


Sub AgeCalc( ) 


      ‘variable declaration (变量声明) 


      Dim FullName As String 


      Dim DateOfBirth As Date 


      Dim Age As Integer 


      'assign values to variables (赋值给变量) 


      FullName = "John Smith" 


      DateOfBirth = #01/03/1967# 


      'calculate age (计算年龄) 






      Age = Year(Now())-Year(DateOfBirth) 


      'print results to the Immediate window (在立即窗口里打印结果) 






      Debug.Print FullName & " is " & Age & " years old." 


End Sub 


(译者:Debug是非常好的工具,它让对象在运行时将结果在立即窗口上显示) 


变量在程序的开始部分就被声明了,从那里开始,它们就可以使用了。在上面的过程里,每个变量 


声明在分开的行。如果你想,你也可以同时在一行里声明好几个变量,用逗号分开每个变量,例如: 






Dim FullName As String, DateOfBirth As Date, Age As Integer 


注意,关键字Dim只在变量声明行的开头出现了一次。 


当VB执行变量声明语句时,它产生了有确切名称的变量,并且占用内存空间来储存它们的值,然后, 


明确的值被赋给这些变量。如何给变量赋值?变量名称,之后是一个等号,等号的右边是你希望用 


该变量储存的数据。这里你输入的数据必须是该变量声明的数据类型。文本数据应该使用引号包括 


起来,而日期需要用井号#包括起来。VB使用DateOfBirth提供的数据来计算员工的年龄,并且将计 


算结果储存到Age这个变量。员工的姓名和年龄通过指令Debug.Print打印到立即窗口。当程序运行 






                                   71 




----------------------- Page 88-----------------------


结束后,你必须打开立即窗口来查看结果。 


我们来看看你声明了错误的数据类型,会发生什么情况。下面的过程是计算一个工作表里的总单元 


格数目,并且将结果使用一个对话框显示给用户。 


Sub HowManyCells( ) 


      Dim NumOfCells As Integer 


      NumOfCells = Cells.Count 


      MsgBox "The worksheet has " & NumOfCells & " cells." 






End Sub 


错误的数据类型会导致错误。在上面的过程里,当VB尝试将Cells.Count语句的结果赋给变量 


NumOfCells时失败,Excel显示信息“运行时间错误6——溢出”。这个错误的产生原因时变量的无 


效数据类型,工作表里单元格总数目不在Integer数据范围之内。要更正这个问题,你应该选择一 


个可以包含一个大数据的数据类型。然而,要快速地解决上面程序遇到的问题,你只要删除变量类 


型As Integer就行了。当你重新运行这个过程时,VB将给你的变量分配为Variant类型,尽管Variant 


比其它变量类型使用更多的内存和降低程序运行速度(因为VB不得不做额外的工作区检查变量类 


型),但是,如果这是在一个简短的程序里,使用Variant的代价也是难以觉察的。 


技巧3-6 变量类型是什么? 


通过下述方法,你可以快速地查明你程序里使用的变量的类型:在变量名称上单击右键,并且从快 


捷菜单上选择“快速信息”。 


技巧3-7 串联 


你可以将两个或多个字符串结合成为一个新的字符串。这个操作称为串联。你已经在AgeCalc和 


HowManyCellss过程里看到了串联的例子。串联用&符号在表示。例如,“His name is ” & FirstName 


将会产生下述字符串:His name is John,或者His name is Michael。人名取决于变量FirstName 


的内容。注意,在is和结束引号之间有一个空格。字符串的串联也可以使用加号(+)来代表,然 


而,许多程序员为了消除混淆,宁愿将加号限制于数字的运算。 






6 明确变量的数据类型 






如果你在Dim语句里没有明确变量的数据类型,你最终将得到没有归类的变量。没有归类的包括, 


在VBA里,总是当成Variant数据类型。高度建议你产生归类了的变量。当你声明变量为某种数据类 


型,你的VBA程序会运行得更快一些,因为VB不需要停下来分析Variant变量到底是什么类型。 


VB可以使用很多种数字变量。Integer变量只能保存从–32,768到32,767之间的所有整数。其它类 


型的数字变量有Long,Single,Double和Currency。Long变量可以保存从–2,147,483,648到 


2,147,483,647范围的所有整数。与Integer和Long相反,Single和Double变量可以保存小数。String 


变量用来引用文本。当你声明了一个String数据类型的变量时,你最好告诉VB这个字符串有多长, 


例如: 


Dim extension As String * 3 


声明变量extension字符串的长度为3个字符。如果你不给它分配一个明确的长度,这个字符串变量 


将是动态的。这意味着VB将会占用足够大的电脑内存来处理任意容量的文本。声明了变量后,你只 


能保存声明语句里显示的信息类型。给数字类型的变量赋文本值,或给文本类型变量赋数字值,都 


会导致“类型不匹配”的错误信息,或者导致VB修正该值。例如,如果你的变量声明为保存整数, 


而你的数据是小数, 那么VB会忽略小数部分而只用数据的整数部分。试验一下下面的MyNumber过 


程,看看VB是如何修正数据以适合变量数据类型的: 


Sub MyNumber() 


      Dim myNum As Integer 


      myNum = 23.11 


      MsgBox myNum 


End Sub 


如果你不用Dim语句声明变量,你通过在变量名称后面加上一个特殊字符同样可以指明该变量的类 


型。例如下面,你可以在变量名称后面附上美元($)符号,来指明变量FirstName为字符串类型 


(String): 


Dim FirstName$ 






                                  72 




----------------------- Page 89-----------------------


上面的声明和Dim FirstName As String是一样的。其它类型的声明字符列在表3-2里面。 


表3-2 类型声明字符 


数据类型                        字符 


Integer                     % 


Long                        & 


Single                      ! 


Double                      # 


Currency                    @ 


String                      $ 






注意,类型声明字符只能用于六种数据类型。将这些字符附在变量名称后面就可以使用这些类型声 


明字符了。过程AgeCalc2示范表3-2中类型声明字符的使用情况: 


Sub AgeCalc2() 


       'variable declaration (变量声明) 


       Dim FullName$ 


       DateOfBirth As Date 


       Dim Age% 


       'assign values to variables (给变量赋值) 


       FullName$ = "John Smith" 


       DateOfBirth = #01/03/1967# 


       'calculate age (计算年龄) 






       Age% = Year(Now())-Year(DateOfBirth) 


       'print results to the Immediate window (在立即窗口里输出结果) 


       Debug.Print FullName$ & " is " & Age% & " years old." 






End Sub 


技巧3-8 声明变量类型 


变量类型可以用As后面的关键字来标示,也可以用后面附加的类型符号来标示。如果你既不加类型 


符号也不使用As命令,那么这个变量将为默认的类型,那就是VBA中的Variant类型。 






7 变量赋值 






既然你已经知道如何命名和声明变量了,是时候开始使用它们了。我们以学习如何创建变量开始。 


在VB中,你可以在你程序的任何地方创建变量,只有给它赋个值就行。 


1. 打开一个新工作簿并且保存为Chap03.xls 


2. 激活VB编辑器窗口 


3. 在工程浏览器窗口,选择这个新的工程并在属性窗口里将它的名称改为Chap03 


4. 选择“插入”-“模块”在工程Chap03里面添加一个新模块 


5. 在属性窗口将该模块名Module1改为Variables 


6. 在代码窗口,输入CalcCost过程,如下面所示。这个过程基于下述假设来计算购买一个计算器 


    的价钱:计算器的价格为35美元,销售税为8.5% 


Sub CalcCost() 


       slsPrice = 35 


       slsTax = 0.085 


       Range("A1").Formula = "The cost of calculator" 


       Range("A4").Formula = "Price" 


       Range("B4").Formula = slsPrice 


       Range("A5").Formula = "Sales Tax" 


       Range("A6").Formula = "Cost" 


       Range("B5").Formula = slsPrice * slsTax 






       Cost = slsPrice + (slsPrice * slsTax) 


       With Range("B6") 






                                        73 




----------------------- Page 90-----------------------


            .Formula = Cost 


            .NumberFormat = "0.00" 


      End With 


      strMsg = "The calculator total is " & "$" & Cost & "." 






      Range("A8").Formula = strMsg 


End Sub 


过程CalcCost使用了四个变量:slsPrice,slsTax,Cost和strMsg。因为这些变量都没有显式声明, 


所以它们的数据类型都是Variant。变量slsPrice和slsTax是在过程的开始时通过给它们赋值而产 


生的,变量Cost分配的值是下面计算的结果:slsPrice + (slsPrice * slsTax)。价格的计算是使 


用变量slsPrice和slsTax提供的值来进行的。变量strMsg将信息合并为一个文本信息给用户,然后 


这个信息是在工作表的一个单元格里输入一个完整的句子。 


当你给变量赋值时,需要在变量名称后面输入一个等号,等号之后是你要输入的值。它可以是数字, 


公式或者带引号的文本。赋给变量slsPrice,slsTax和Cost的值比较容易理解,然而保存在变量 


strMsg的值则有些棘手。我来解释一下变量strMsg的内容吧。 






strMsg = "The calculator total is " & "$" & Cost & "." 






  字符串“The calculator total is ”被引号包括起来了,注意,后面的引号前有个空格。 


  字符&让你将一个字符串附加在另一个字符串或者变量的内容后面 


  在引号里面的美元符合(“$”)用来表明货币类型。因为美元符合是字符,它需要用引号来 


   包括起来 


  字符&必须用于每次你要在前面的字符串后加新信息的时候 


  变量Cost是一个占位符,当过程运行时,计算器的实际价格将显示在这儿 


  字符&可以连接任何字符串 


  句号用引号包括起来。当你需要在句子后面加句号时,如果它是在一个变量后面时,你必须单 


   独再在后面加上它。 


现在来运行它,将光标放在过程CalcCost的任何地方,并且选择“运行”-“运行宏” 


技巧3-9 变量初始化 


VB创建变量的时候就将其初始化了。变量假定为它们的默认值,数字型变量设置为0,布尔型变量 


初始化为False,字符串变量设置为空字符(””),已经日期型变量则设置为1899年12月30日 


注意,你在运行这个过程时,VB可能会弹出下面的信息:“编译错误:变量未定义”。如果这个情况 


发生了,点击确定以关闭这个信息框。VB将会选中变量slsPrice并且加亮过程名称Sub CalcCost, 


标题栏则显示“Microsoft Visual Basic-Chap03.xls [中断]”。VB中断模式允许你在继续之前更 


正错误。在本书的后面,你将学习如何在中断模式下解决问题。就现在而言,如果你遇到上面提及 


的错误时,通过选择“运行”-“重新设置”来退出中断模式;接下来,在代码窗口的上面删除显 


示在第一行的语句Option Explicit。Option Explicit语句意味着在本模块里使用的所有变量都必 


须经过正式声明。你将在下一节里学习这个语句。删除Option Explicit语句后,重新运行该过程, 


运行后,切换到Excel界面,过程运行的结果应该和图3-1一致。 






图3-1 VBA过程可以在工作表里输入数据并计算结果 


单元格A8显示变量strMsg的内容。注意,在单元格B6里面输入的价格有两位小数,而strMsg的价格 


却显示三位小数。要在单元格A8里显示带两位小数的计算器价格,你必须给变量Cost设置需要的格 






                                   74 




----------------------- Page 91-----------------------


式,而不是给该单元格设置格式。VBA有专门的函数让你改变数据格式,你将使用Format函数来改 


变变量Cost的格式。该函数的语法是: 


Format(expression, format) 


Expression(表达式)是你要设置格式的值或者变量;format(格式)则是你要使用的格式类型。 


1. 在CalcCost过程里更改变量Cost的计算: 


Cost = Format(slsPrice + (slsPrice * slsTax), "0.00") 


2. 将With…End With代码块取代为下述指令: 


Range("B6").Formula = Cost 


3. 将语句Range("B5").Formula = slsPrice * slsTax改为下面指令: 






Range("B5").Formula = Format((slsPrice * slsTax), "0.00") 


4. 重新运行修改后的程序 


试验过程CalcCost之后,你可能会困惑,为什么我们要为声明变量烦恼,如果VB自己可以处理未声 


明的变量的话?因为过程CalcCost是如此之短,因此你不必担心VB每次使用这些Variant变量时会 


占用多少内存。然而,在短的过程中,内存问题不重要,但是当你输入变量名称时,你很可能出现 


错误。当你第二次使用Cost变量时,你忽略了“o”而写成“Cst”,后果会如何呢? 


Range("B6").Formula = Cst 


如果你使用了Tax在下面的公式中,而没有用slsTax,结果你将得到什么呢? 


Cost = Format(slsPrice + (slsPrice * Tax), "0.00") 






引入上面提及的错误后过程CalcCost的结果显示在图3-2。 






图3-2 变量名称错误导致结果错误 


注意,在图3-2里,单元格B6没有数值,因为VB没有找到变量Cst的任务语句。再因为VB不知道销 


售税,显示的计算器价格为总价(而没有加税金,见单元格A8)。VB不会猜测,它只是简单地做你 


告诉它的事情。这带我们到下一个部分,解释如何避免这类错误。在你继续之前,确保更正变量Cst 


和Tax为Cost和slsTax。 






8 强制声明变量 






VB使用Option Explicit语句自动提醒你正式地声明你的变量,这个语句必须放在每个模块的最上 


面。如果你试图运行一个含有未定义的变量的过程时,Option Explicit语句会让VB产生一个错误 


信息。 


1. 返回代码窗口你输入过程CalcCost的地方 


2. 在模块的最上面输入Option Explicit并回车,Excel将该语句显示为蓝色 


3. 运行过程CalcCost,VB显示错误信息“编译错误:变量未定义” 


4. 点击确定关闭信息框。 


   VB加亮变量名称slsPrice。现在你需要正式声明这个变量。当你声明了变量slsPrice并再次运 


   行该过程时,VB一旦遇到另外一个未声明的变量时,将再次产生同样的错误。 


5. 在CalcCost过程的开始部分输入下述声明: 


    'declaration of variables (声明变量) 


    Dim slsPrice as Currency 


    Dim slsTax as Single 






                                    75 




----------------------- Page 92-----------------------


    Dim Cost as Currency 


    Dim strMsg as String 


6. 按下F5来运行该过程,修改后的程序显示如下“ 


Option Explicit 


Sub CalcCost() 


'declaration of variables 


      Dim slsPrice As Currency 


      Dim slsTax As Single 


      Dim Cost As Currency 


      Dim strMsg As String 


      slsPrice = 35 


      slsTax = 0.085 


      Range("A1").Formula = "The cost of calculator" 


      Range("A4").Formula = "Price" 


      Range("B4").Formula = slsPrice 


      Range("A5").Formula = "Sales Tax" 


      Range("A6").Formula = "Cost" 


      Range("B5").Formula = Format((slsPrice * slsTax), "0.00") 






      Cost = Format(slsPrice + (slsPrice * slsTax), "0.00") 


      With Range("B6").Formula = Cost 


      strMsg = "The calculator total is " & "$" & Cost & "." 






      Range("A8").Formula = strMsg 


End Sub 


在模块上面输入的Option Explicit语句强迫你声明变量,因为如果你需要声明变量的话,你必须 


每次在添加新模块时输入Option Explicit语句,所以你可以让VB帮你输入它。按照下述步骤来自 


动在新模块里添加Option Explicit语句: 


1. 选择“工具”-“选项” 


2. 确保选项对话框(编辑器页)上的“要求变量声明”被勾选上了 


3. 点击确定关闭对话框 


从现在开始,每个新模块都会在第一行添加Option Explicit语句。如果你要在一起创建的模块里 


强制声明变量的话,你必须手动输入Option Explicit。 


技巧3-10 Option Explicit更多信息 


Option Explicit强迫正式(显式)声明模块里的所有变量。使用它的一个重大优点是,输入错误 


会在编译时(VB试图将源代码翻译为可执行代码)被检测到。Option Explicit语句必须在模块里 


的任何过程之前出现。 






9 了解变量范围 






不同的变量在VBA过程里有不同的影响范围。Scope(范围)这个术语定义某个特定的变量在同一个 






过程,其它过程,或者其它VBA工程里的可用性。变量在VBA里可以是下面三种级别的范围: 


  过程级别范围 


  模块级别范围 


  工程级别范围 






10 过程级别(当地)变量 






从本章起,你已经知道如何通过关键字Dim来声明变量,在关键字Dim在模块中的位置决定了该变量 


的范围。在VBA过程中用Dim关键字声明的变量拥有过程级别的范围,过程级别的变量经常被称为当 


地变量。当地变量只能使用在声明它的过程里面。未声明的变量总是过程级别的变量。在它的范围 


内,变量的名称必须是唯一的,这意味着你不可以在同一个过程里使用同样的名称来声明两个变量。 


然而,你可以在不同的过程里面使用同样的变量名称。换句话说,过程CalcCost里可以有slsTax 


变量,同一个模块里的过程ExpenseRep里页可以有它自己的变量slsTax,两个变量相互独立。 






                                      76 




----------------------- Page 93-----------------------


11 模块级别变量 






当地变量有助于节省电脑内存,一旦该过程结束,该变量便立即消失,并且电脑释放该变量占用的 






内存空间。然而,在编程中,你经常需要变量在本过程结束后仍然在其它过程里可用,这种情形需 


要你改变变量的范围。你可能就需要定义一个模块级别的变量,而不是过程级别的了。要定义模块 


级别的变量的话,你必须将关键字Dim放在模块表里任何过程的上面(紧接着在关键字Option 


Explicit的下面)。例如,将slsTax设置为任何Variables模块里的过程都可以使用,按照下述方法 


声明slsTax变量: 


Option Explicit 


Dim slsTax As Single 


Sub CalcCost( ) 


      <放置过程指令> 


End Sub 


在上面的例子里,关键字Dim在模块的上面,紧挨着Option Explicit语句。你需要另外一个过程来 


使用变量slsTax,这样你才能查看这是如何工作的。 


1. 在代码窗口里,将变量声明行Dim slsTax As Single从Variables模块的CalcCost过程里剪切, 


   并且粘贴到该模块的上面Option Explicit语句的下面 


2. 在CalcCost过程的同一个模块里输入ExpenseRep过程代码: 


Sub ExpenseRep() 


    Dim slsPrice As Currency 


    Dim Cost As Currency 


    slsPrice = 55.99 






    Cost = slsPrice + (slsPrice * slsTax) 


    MsgBox slsTax 


    MsgBox Cost 


End Sub 


ExpenseRep过程里声明了两个货币类型的变量:slsPrice和Cost。slsPrice变量随后赋值55.99, 


slsPrice和CalcCost过程里声明的变量slsPrice是独立工作的。ExpenseRep过程计算采购的费用, 


该费用包括销售税,因为销售税和CalcCost过程里使用的是一样的,所以将slsTax变量声明为模块 


级别的变量。VB执行CalcCost过程后,变量slsTax的内容等于0.085。如果slsTax是当地变量的话, 


随着CalcCost过程的终结,变量slsTax的内容将被清空。过程ExpenseRep结束时显示两个信息框来 


输出变量slsTax和Cost的值。当你运行CalcCost后,VB清空除了slsTax之外的所有变量的内容,因 


为slsTax以被定义为模块级别的变量。一旦你试图通过运行ExpenseRep来计算价格,VB就会找到 


slsTax的值,并且将它用到计算中。 


技巧3-11 私有变量 


当你在模块级别声明变量时,除了关键字Dim之外,你还可以使用关键字Private。例如, 


Private slsTax As Single 


私有变量仅仅在声明该变量的模块里的过程中可用。私有变量总是在模块的上面Option Explicit 


语句之后声明。 


技巧3-12 保持工程级别的变量为私有 


为了避免工程级别的变量内容被工程之外使用,你可以在Option Explicit语句下面,模块的上面 


输入Option Private Module,例如: 


Option Explicit 


Option Private Module 


Public slsTax As Single 


Sub CalcCost( ) 


      <这里是过程代码> 


End Sub 






12 工程级别变量 






模块级别的变量用关键字Public(而不是Dim)声明时,拥有工程级别范围。这意味着它们可以在 






                                    77 




----------------------- Page 94-----------------------


VBA任何模块里使用。当你想要在一个打开的VBA工程的所有过程里使用某个变量时,必须用Public 


关键字来声明它,例如: 


Option Explicit 


Public slsTax As Single 


Sub CalcCost( ) 


      <过程代码> 


End Sub 


注意,变量slsTax在模块上面以Public关键字声明的,它将会在该VBA工程里的任何过程里都可用。 






13 变量的存活期 






除了范围之外,变量还有存活期,变量的存活期决定了该变量能保存它的值有多久。一旦该工程打 


开,模块级别和工程级别的变量就会保留它们的值。然而,如果程序的逻辑需要,VB能够重新初始 


化这些变量。使用Dim语句声明的当地变量当过程结束时就会丢失值,当地变量的存活期是随着过 


程的运行的,并且它们在程序每次运行的时候可以被重新初始化。VB允许你通过改变声明方式延长 


当地变量的存活期。 






14 了解和使用静态变量 






用Static关键字声明的变量是特殊的当地变量,静态变量在过程级别声明。和那些用关键字Dim声 


明的当地变量相反,静态变量在程序已经不在它们的过程里时仍然不会丢失它们的内容。例如,当 


一个带有静态变量的VBA过程调用另外一个过程时,在VB执行完被调用的过程语句后返回主调过程 


时,静态变量仍然保留它原来的值。过程CostOfPurchase示范静态变量allPurchase的使用: 


Sub CostOfPurchase() 


    'declare variables 


    Static allPurchase 


    Dim newPurchase As String 


    Dim purchCost As Single 


    newPurchase = InputBox("Enter the cost of a purchase:") 






    purchCost = CSng(newPurchase) 


    allPurchase = allPurchase + purchCost 


    'display results 






    MsgBox "The cost of a new purchase is: " & newPurchase 


    MsgBox "The running cost is: " & allPurchase 






End Sub 


上面的过程以一个名为allPurchase的静态变量和两个当地变量newPurchase和purchCost的声明开 


始。该过程中使用的InputBox函数显示一个对话框并且等着用户输入数值,一旦用户输入数值并且 


点击确定后,VB就会将该数值赋给变量newPurchase。在第四章中有InputBox函数的讨论。因为 


InputBox函数的结果总是字符串,变量newOurchase被声明为字符串数据类型了。然而,你不能在 


数学计算中使用字符串,这就是为什么需要在下一指令中使用一个类型转换函数(CSng)来将字符 


串值转换为单精度浮点类型的数字。函数CSng只需要一个自变量——你要转换的数值。函数CSng 


转换的数字结果保存在变量purchCost上。 


技巧3-13 类型转换函数 


在CSng上的任意地方按下F1,可以查看更多关于函数CSng的信息(也可以查看其它类型转换函数信 


息) 


下一行指令:allPurchase = allPurchase + purchCost,将InputBox函数提供的新数值加和到目 


前的采购数值上。当你第一次运行这个过程的时候,变量allPurchase和变量purchCost的内容是一 


样的;当你第二次运行它的时候,这个静态变量的值由对话框提供的值增加了。你可以随意多次运 


行过程CostOfPurchase,只要该工程是开着的,变量allPurchase就会不断的变化。依照下述步骤 


来试验该过程: 


1. 将光标放在过程CostOfPurchase里的任意地方并且按下F5 


2. 当对话框出现时,输入一个数字,例如,输入100然后回车。VB显示信息““The cost of a new 


   purchase is: 100.” 


                                   78 




----------------------- Page 95-----------------------


3. 点击确定,VB显示第二个信息“The running cost is: 100.” 


4. 重新运行该程序,当对话框出现时,输入另外一个数字,例如输入50再回车。VB显示信息“The 


    cost of a new purchase is 50.” 


5. 点击确定,VB显示第二个信息“The running cost is: 150.” 


6. 多次运行该程序,看看VB是如何追踪运行的总量的。 






15 声明和使用对象变量 






你已经学习的变量是用于储存数据的,储存数据是你使用“普通的”变量的主要原因。除了储存数 


据从普通变量之外,还有引用VB对象的特殊变量,这些变量称为对象变量。你在第二章中已经学习 


了多种对象,现在,你开始学习如何用对象变量来代表对象。对象变量不储存数据,它们告诉数据 


在哪儿。例如,你可以用对象变量告诉VB数据在当前工作表的单元格E10,对象变量使定位数据更 


容易。编写VB程序时,你经常需要写一些很长的指令,例如: 






Worksheets("Sheet1").Range(Cells(1,1), Cells(10, 5).Select 


你可以声明一个对象变量来告诉VB数据在哪儿,而不必使用很长的指令来指向该对象。对象变量的 


声明和你已经学习的变量声明类似,唯一的不同是在关键字As后面,你输入词语Object作为数据类 


型,例如: 


Dim myRange As Object 


上面的语句声明了一个叫做myRange的对象变量。然而,实际上只声明对象变量是不够的,在使用 


这个变量于程序里之前,你还给这个对象变量赋上确定的值。使用关键字Set来给对象变量赋值, 


关键字Set后面是等号,再后面是该变量指向的值,例如: 


Set myRange = Worksheets("Sheet1").Range(Cells(1,1), Cells(10, 5)) 


上面的语句给对象变量myRange赋值,这个值指向工作表Sheet1的单元格区域A1:E10。如果你忽略 


了关键字Set,VB将会显示一个错误信息——“运行时间错误91:对象变量或With块变量未设置”。 


现在,又是来看看实例的时候了,下面的过程UseObjVariable示范一个叫myRange的对象变量的使 


用: 


Sub UseObjVariable() 


      Dim myRange As Object 


      Set myRange = Worksheets("Sheet1"). _ 


            Range(Cells(1, 1), Cells(10, 5)) 






      myRange.BorderAround Weight:=xlMedium 


      With myRange.Interior 


            .ColorIndex = 6 


            .Pattern = xlSolid 


      End With 






      Set myRange = Worksheets("Sheet1"). _ 


            Range(Cells(12, 5), Cells(12, 10)) 


      myRange.Value = 54 


      Debug.Print IsObject(myRange) 


End Sub 


我们来逐行分析一下过程UseObjVariable里的代码。过程开始的时候是对象变量myRange的声明, 


下一行将对象变量设置未Sheet1的区域A1:E10。从现在开始,你每次要引用这个区域时,你不需要 


写下整个地址,而只要使用这个捷径——该对象变量名称就可以了。这个过程的目的是在区域 


A1:E10外围设置边框,你不必使用下面这样冗长的指令: 






Worksheets("Sheet1").Range(Cells(1, 1), _ 


      Cells(10, 5)).BorderAround Weight:=xlMedium 






而可以使用一个捷径,使用对象变量名称: 


myRange.BorderAround Weight:=xlMedium 


下一节语句是将选区A1:E10设置底色。同样,你不需要使用你要操作的对象的冗长地址,你可以使 


用简单的对象变量名称myRange。下一句代码是给对象变量myRange分配一个新的引用区域,VB将忘 


记老的引用,你下次使用myRange时,它会引用另一个区域E12:J12。在新区域(E12:J12)输入了 






                                     79 




----------------------- Page 96-----------------------


54后,过程给你显示如何确定某个变量时对象类型。如果myRange是对象变量的话,指令Debug.Print 


IsObject(myRange)将在立即窗口里面输入True。IsObject是个VBA中指明某变量是否是对象变量的 


函数。 


技巧3-14 使用对象变量的好处 


使用对象变量的好处有: 


  它们可以代替真实对象使用 


  它们比真实对象更短更容易记住 


  当过程运行时,你可以改变它们的意义 






16 使用明确的对象变量 






对象变量可以引用任意一种对象,因为VB有很多种对象,所以,要让你的程序可读性更强,运行更 


快,最好创建引用到具体对象类型的对象变量。例如,在过程UseObjVariable中,你可以将myRange 


对象变量声明为Range对象,而不是通常的对象变量(Object): 


Dim myRange As Range 


如果你要引用一个具体的工作表,你可以声明Worksheet对象: 


Dim mySheet As Worksheet 


Set mySheet = Worksheets("Marketing") 






当对象变量不再需要时,你可以给它赋值Nothing,这将释放内存和系统资源: 


Set mySheet = Nothing 


你将在第九章里看到更多的使用对象变量的例子。 






17 查找变量定义 






当你在VBA过程里看到一行给变量赋值的指令时,你可以通过选择该变量名称并且按下Shift+F2, 


快速地定位到该变量的定义(声明)。或者,你也可以选择“视图”-“定义”,VB将跳到变量的声 


明行。要回到刚才的位置,只要按下Ctrl+Shift+F2或选择“视图”-“最后位置”。我们来试试: 


1. 定位到过程CostOfPurchase的代码里 


2. 定位到语句purchCost = CSng(newPurchase) 


3. 在变量名称上单击右键,并在快捷菜单上选择“定义” 


4. 通过按Ctrl+Shift+F2返回刚才位置 


5. 试试在其它过程的其它变量上查找定义,每次使用不同的方法跳到声明位置。 


技巧3-15 这个变量是什么类型? 


你可以使用一个VB内置函数来查明变量的类型。参见第四章中使用函数VarType的例子。 






18 在 VB 过程里面使用常量 






当你的程序运行,变量的内容是可以变化的,如果你想要一次又一次地引用不变的值,那么你应该 


使用常量。常量就像一个指定的变量一样,总是引用这个相同的值。VB要求你在使用前要声明常量。 


正如下述例子,使用Const语句来声明常量: 


Const dialogName = "Enter Data" As String 






Const slsTax = 8.5 


Const ColorIdx = 3 


常量,象变量一样拥有范围。要让常量仅在一个过程里可用,将它声明为过程级别即可,例如: 


Sub WedAnniv( ) 


    Const Age As Integer = 25 






    <place procedure instructions here> 


End Sub 


如果你想要某个常量在一个模块的所有过程中都可用,则在Const语句前加上关键字Private就可 


(译者:写在所有过程之上),例如: 


Private Const dsk = "B:" As String 


私有常量必须在模块的上面,第一个Sub语句之上声明。 


如果你要创建一个该工作簿所有模块都可用的常量时,在Const语句之前加上Public关键字就可以 


了,例如: 






                                   80 




----------------------- Page 97-----------------------


Public Const NumOfChar = 255 As Integer 






公共常量必须在模块的上面,第一个Sub语句之上声明。 


声明常量的时候,你可以使用下列数据类型之一:Boolean,Byte,Integer,Long,Currency,Single, 


Double,Date,String或者Variant。 


象变量一样,多个常量也可以在一行里声明,例如: 


Const Age As Integer = 25, City As String = "Denver", PayCheck As Currency = 350 


使用常量可以使你的VBA过程可读性强,容易维护。例如,你在程序里多次引用某个特定值,就可 


以使用常量,而不是这个值本身。这样,如果以后这个值变了(例如销售税率上升了),你只要简 


单地在Const语句里改变这个常量的声明就可以了,而不必追踪该值所有发生的地方。 






19 内置常量 






Excel和VBA都有一长列的预先定义的常量,并且不需要声明,这些内置常量可以通过对象浏览器查 


找,我们已经在第二章里详细讨论了对象浏览器。我们来打开对象浏览器并查找Excel常量清单: 


1. 在VB编辑器窗口,选择“视图”-“对象浏览器” 


2. 在“工程/库”下拉列表里选择Excel 


3. 在搜索文本框里输入“Constants”并回车,VB显示搜索结果在“搜索结果”区域 


4. 在“类”列表框拉下滚动条,选择“Constants”(参见图3-3)。对象浏览器右边区域显示所 


   有Excel对象库里可用的内置常量。注意,所有常量的名称以前缀“xl”开头。 






图3-3 使用对象浏览器查找内置常量 


5. 要查找VBA常量,在工程/库文本框里输入VBA。注意,所有VBA的内置常量以前缀“vb”开头. 


学习内置常量的最好方法是使用宏录制器,我们来花上几分钟来录制最小化当前窗口的过程: 


1. 在Excel窗口,选择“工具”-“宏”—“录制新宏” 


2. 输入MiniWindow作为宏名,选择“当前工作簿”作为保存宏的地方,然后确定 


3. 点击最小化按钮,确保你最小化了本文件的窗口,而不是Excel应用程序窗口 


4. 点击“停止录制”按钮 


5. 最大化该被最小化了的窗口 


6. 切换到VB编辑器窗口,并且双击模块文件夹。代码显示如下: 


Sub MiniWindow( ) 


      ActiveWindow.WindowState = xlMinimized 






End Sub 


你有时可能会看到VBA过程使用数值,而不是内置常量名称,例如,常量xlMaximized的实际数值是 


-4137,常量xlMinimized的值是-4140,以及常量xlNormal的值为-4143(参见图3-4) 






                                  81 




----------------------- Page 98-----------------------


图3-4 你可以在对象浏览器里面选择常量名称然后在下面的窗口里看到它的实际值 






20 接下来…… 






本章介绍了几个VBA概念,包括数据类型,变量和常量。你学习了如何声明各种变量,也看到变量 


和常量之间的区别。既然你知道什么是变量,也知道如何使用它们,你就可以创建使用比前两章更 


有意义的方法操作数据的过程了。在下一章中,你将通过使用带有自变量和函数的过程来扩展你的 


VBA知识,另外,你还将学习函数,让你的VBA过程与用户进行交流。 






                        第四章 VBA 过程:子程序和函数 






作者:Julitta Korol  翻译:Tiger Chen Jan 16’ 2005 


在第二章中,你知道了过程是一组指令,它让你在程序运行的时候完成一些具体的任务。VBA有以 


下三种过程: 


  子程序过程(子程序)执行一些有用的任务但是不返回任何值。它们以关键字Sub开头和关键 


   字End Sub结束。子程序可以用宏录制器(第一章)录制或者在VB编辑器窗口里直接编写(见 


   第二章和第三章)。在你第一章里已经学习了多种运行这种过程的方法。 


  函数过程(函数)执行具体任务并返回值。它们以关键字Function开头和关键字End Function 


   结束。在本章中,你将创建你的第一个函数过程。函数过程可以从子程序里执行,也可以从工 


   作表里访问,就像Excel的内置函数一样。 


   属性过程用于自定义对象。使用属性过程你可以设置和获取对象属性的值,或者设置对另外一 


   个对象的引用。你将在第十一章中学习如何创建自定义对象和使用属性过程。 


在本章中,你将学习如何创建和执行自定义函数,另外,你将发现变量(见第三章)如何用于传递 


数据给子程序和函数。在本章后面,你将对VBA中两种最有用的函数:MsgBox和InputBox进行比较 


彻底的了解。 






1.关于函数过程 






使用Excel几百种内置函数,你可以进行非常宽广的自动计算,然而,你总有要做个自定义计算的 


时候。使用VBA编程,你可以通过创建函数过程快速的完成这个特殊需求,你可以创建任何Excel 


没有提供的函数。 






2.创建函数过程 






象Excel函数一样,函数过程进行计算并返回数值。学习函数的最好方法就是自己创建一个。因此, 


我们开始吧。设置完一个新的VBA工程后,你将创建一个函数过程来加和两个数值。 


1. 打开一个新Excel工作簿,并保存为Chap04.xls 


2. 切换到VB编辑器窗口并且选择VBAProject(Chap04.xls) 


3. 在属性窗口,将VBAProject改为MyFunctions 


4. 在工程浏览器窗口选择MyFunctions(Chap04.xls),然后选择“插入”-“模块” 


5. 在属性窗口将“模块1”改为Sample1 






                                    82 




----------------------- Page 99-----------------------


6. 在工程浏览器窗口,点击Sample1并选择“插入”-“过程”(译者:需要激活右边的代码窗口)。 


   添加过程对话框如图4-1所示 






图4-1 你使用添加过程对话框时,VB自动创建你选择的过程类型 


7. 在对话框里输入下列设置: 


   名称:SumItUp 


   类型:函数 


   范围:公共的 


8. 点击确定退出添加过程对话框。VB输入了一个空函数过程如下: 


Public Function SumItUp() 


End Function 


第一句声明函数过程名称,关键字Public表面这个函数可以在所有模块的所有过程里访问。关键字 


Public是可选的。注意,关键字Function后面是函数名称(SumItUp)和一对空括号。在括号里你 


可以列上计算中需要的数据项目。每个函数过程都以End Function语句结束。 


技巧4-1 关于函数名称 


函数名称应该点明该函数的作用,并且必须和变量的命名规则一致。 


技巧4-2 设置VBA过程范围 


在前几章你学习了变量的范围决定它可以在哪些模块和过程里使用,和变量一样,VBA过程也有范 


围。过程的范围决定其它模块里的过程是否可以调用该过程。所以的VBA过程默认为公共的,这意 


味着它可以被任何模块里的其它过程调用。因为过程默认为公共的,所以如果你愿意你可以忽略关 


键字Public。但是,如果你将Public关键字换成关键字Private,那么你的过程只能被同一模块里 


的其它过程调用,而不能被其它模块里的过程调用。 


9. 将函数声明修改为这样: 


Public Function SumItUp(m,n) 


End Function 


这个函数的目的是加和两个数值。不要将实际值输给函数。给该函数提供两个自变量以确保该函数 


具有灵活性。这样,你的自定义函数就能够将你提供的任何两个数值加和起来了。每个变量代表一 


个数值,你在运行该函数时要给每个变量提供数值。 


技巧4-3 使用函数的理由 


自定义VBA函数可以用于: 


  分析数据和进行计算 


  修正数据和汇报信息 


  基于提供的或计算的数据采取具体行动 


10. 在Public Function和End Function之间输入下述语句: 


SumItUp = m + n 


这条语句意思是将储存于变量n上的数据加在储存于变量m的数值上,并且将结果返回给函数 






                                  83 




----------------------- Page 100-----------------------


SumItUp。在等号后面输入该函数名称,再就是括号和需要加和的数值。在上面的语句中,设置函 


数名称等于m + n的和。完成的自定义函数过程如下: 


Public Function SumItUp(m,n) 


      SumItUp = m + n 


End Function 


祝贺,你已经创建了你的第一个函数!然而,函数过程并没有什么用,除非你知道如何执行它。下 


一个段落将给你示范如何使你的函数工作。 






3.执行函数过程 






在第一章里,你学习了很多中方法来运行子程序。和子程序不同,函数过程只能使用两种方法来执 






行。你可以用于工作表的公式里面,或者从另外一个过程里调用它。你在VBA里创建的函数过程, 


不能通过在Excel窗口选择“工具”-“宏”-“运行宏”访问;它们也不能在代码里面通过按F5 


键来运行。接下来的部分里,你将学习到执行函数的专门技术。 






4.从工作表里运行函数过程 






自定义函数过程和内置函数一样,如果你不知道确切的函数名称或者它的自变量,那么你可以使用 






“插入函数”对话框来帮助你在工作表里输入需要的函数。 


1. 切换到Excel窗口,并选择任何一个单元格 


2. 点击函数工具栏上的“插入函数(fx)”按钮(译者:或者选择“插入”-“函数”),Excel 


   弹出插入函数对话框,上面显示了所选类别里所以函数,按字母顺序排列 


3. 在类别下拉框里选择“全部”或者“用户定义”,然后滚动函数名称框,找到并选择本章中创 


   建的函数SumItUp。当你选中这个函数名称时,在插入函数对话框的下部显示了该函数的语法: 


   SumItUp(m,n)(译者:同时可以看到“没有帮助信息”。请参阅创建自定义函数的相关教材, 


   如何给自定义函数提供帮助信息) 


技巧4-4 私有函数用户是看不到的 


使用关键字Private声明的函数不会出现在“插入函数”对话框上,私有函数不能用于公式里,它 


们只能从另一个VBA过程里调用。 


技巧4-5 快速访问自定义函数 


一旦你创建了一个公共的VBA函数,Excel就会将它加入到“插入函数”对话框的“用户定义”的类 


别里。通过选择这个类别,你可以快速地访问该自定义函数。 






图4-2 VBA自定义函数出现在Excel内置函数同一清单上 


4. 点击确定,开始写公式。“函数参数”对话框出现,如下图所示。对话框显示了函数名称和每 


   个参数:m和n 






                                    84 




----------------------- Page 101-----------------------


图4-3 公式的调色板功能有助于输入任何工作表函数,不论是内置或VBA编程的自定义函数 


5. 如图4-3所示输入自变量数值,或者你任意输入数值。当你输入数值在参数文本框时,Excel 


   显示你输入的数和当前的函数结果。因为两个参数(m和n)都是必须的,所以,如果你忽略了 


   其中的某个时,函数会返回错误。 


6. 点击确定退出函数参数对话框,Excel输入函数SumItUp在所选的单元格里,并且显示它的结果。 


   要编辑这个公式的话,选择该显示公式结果的单元格,并且点击“插入函数”按钮,选择函数 


   并点击确定以访问函数参数对话框。在函数参数m和n上输入不同的数值,并点击确定。也可以 


   直接在该单元格上双击,修改函数参数值。 


技巧4-6 确保你的自定义函数可用 


只有在你储存该自定义函数的工作簿开启的时候,你的自定义VBA函数才可用,如果你关闭该工作 


簿,该函数便不再可用。要确保你的自定义函数每次在你使用Excel时都能用到,你可以做下述事 


情之一: 


  保存你的函数在个人宏工作簿 


  将含有你的自定义函数的工作簿保存在XLStart文件夹里 


  创建引用到含有该自定义函数的工作簿(请参见第二章,如何创建对另一个工程的引用) 






5.从另外一个 VBA 过程里运行函数过程 






正如前面提到的,你不能在VB窗口将光标放在代码里并且按F5来运行函数,也不能通过选择“运行” 


-“运行宏”来运行函数过程。要运行函数,你必须从另外一个过程里调用该函数。要执行自定义 


函数,编写一个VBA子程序并且在需要的时候调用该函数。下面的过程调用函数SumItUp并且将计算 


结果输出在立即窗口: 


Sub RunSumItUp() 


      Dim m As Single, n As Single 


      m = 370000 


      n = 3459.77 


      Debug.Print SumItUp(m,n) 


      MsgBox "Open the Immediate window to see the result." 






End Sub 


  上面的子程序使用Dim语句声明变量m和n,它们用来给函数提供数据 


  接下来两行语句给变量赋值 


  再下来,VB调用函数SumItUp并且将储存于变量m和n的数值传递给它。当函数过程里SumItUp = 


   m + n语句执行完后,VB返回到子过程RunSumItUp里面,并且使用Debug.Print语句将函数的结 


   果输出在立即窗口 


  MsgBox函数通知用户在哪里查看结果 


依照下述步骤来试验上面的例子: 


1. 在输入函数SumItUp的同一个模块里面输入过程RunSumItUp 


2. 将光标放在该过程的任意地方,按下F5 






                                   85 




----------------------- Page 102-----------------------


技巧4-7 函数的快速测试 


你编写自定义函数后,你可以在立即窗口快速的测试它。打开立即窗口,输入一个问号(?)在函 


数名称前,可以显示该函数的计算结果。记住,要在括号里输入函数的参数值。 例如,输入: 


? SumItUp(54, 367.24) 


然后回车。你的函数使用参数m和n传递的数值进行计算,函数的结果显示在下一行: 


421.24 






6.传递参数 






到目前为止,你已经创建了简单的可以执行具体任务的VBA过程,这些过程在它们运行前没有要求 


你提供额外的数据。然而,在现实生活中,过程(子程序和函数)经常需要参数。参数(自变量) 


是过程工作时需要的一个或多个数值。参数通常输入在括号之间,多个参数用逗号分割开来。使用 


Excel有一阵了,你已经知道Excel内置函数根据你提供的数据可能产生不同的结果。例如,如果单 


元格A4和A5分别含有数字5和10,加和公式=SUM(A4:A5)将会返回15,除非你更改单元格里面的数值。 


正如你可以传递数值给Excel内置函数,你也可以传递数值给自定义VBA过程。现在,我们来看看如 


何从子程序传递数值给函数SumItUp。这个自定义函数目的是计算一个人的姓和名的字母数目。 


1. 在放置函数SumItUp的模块里输入下列子程序NumOfCharacters: 


Sub NumOfCharacters() 


      Dim f As Integer 


      Dim l As Integer 






      f = Len(InputBox("Enter first name:")) 


      l = Len(InputBox("Enter last name:")) 


      MsgBox SumItUp(f,l) 


End Sub 


2. 将光标放在过程NumOfCharacters的任意地方并按下F5。VB将显示信息输入框问你名字,这个 


    信息框由下面的函数产生: 


InputBox("Enter first name:") 


3. 输入任何名字,回车,VB接受你输入的文本并且将它作为一个参数传递给函数Len。函数Len 


    计算提供的文本的字母数目。VB将函数Len的结果储存于变量f以供以后使用。这之后,VB显示 


    下一个信息框,这次是问你的姓。 


4. 输入任何姓,回车。VB将输入的姓传递给函数Len来获得姓的文本长度,然后数值储存于变量l。 


    接下来发生什么呢?VB遇到了函数MsgBox,这个函数告诉VB显示函数SumItUp的结果。然而, 


    因为这个结果还没有准备好,VB很快就跳到函数SumItUp里,使用变量f和l储存的数值来做计 


    算。在函数内部,VB用变量f的值取代参数m和变量l值取代参数n。一旦取代工作完成,VB将两 


    个数值加和起来,并且将结果返回给函数SumItUp。函数SumItUp内部没有其它的任务了,因此, 


    VB又马上返回子程序并且将函数SumItUp的结果作为一个参数提供给函数MsgBox。现在这个信 


    息出现在屏幕上,显示了字母总数目。 


5. 点击确定退出信息框,你可以多次运行过程NumOfCharacters,每次输入不同的姓名。 


我们来看看另外一个使用变量传递参数的例子: 


1. 在工程MyFunctions (Chap04.xls)里添加一个新模块,并重命名为Sample2 


2. 激活模块Sample2并且输入子程序EnterText: 


Sub EnterText() 






      Dim m As String, n As String, r As String 


      m = InputBox ("Enter your first name:") 






      n = InputBox("Enter your last name:") 


      r = JoinText(m, n) 


      MsgBox r 


End Sub 


3. 输入下述函数过程: 


Function JoinText(k,o) 


      JoinText = k + " " + o 






                                    86 




----------------------- Page 103-----------------------


End Function 


4. 运行过程EnterText 


VB执行语句时,它收集用户输入的数据并且将这些数据储存在变量m和n上,然后传递这些数据到函 


数JoinText。VB将这些变量的值取代函数JoinText的参数,并且将结果赋到函数名称(JoinText) 


上。当VB返回过程EnterText时,函数的值储存于变量r。然后,函数MsgBox在信息框里显示变量r 


的内容。结果就是用户的完整姓名(姓和名用空格分开)。要从函数传递数值给子程序,需要将该 


值赋到函数名称,例如,下面的函数NumOfDays将值7传递到子程序DaysInAWeek: 


Function NumOfDays() 


      NumOfDays = 7 


End Function 


Sub DaysInAWeek() 






      MsgBox "There are " & NumOfDays & " days in a week." 


End Sub 


技巧4-8 函数过程不能做什么 


函数过程不能进行任何动作,例如,它们不能在工作表里做插入,删除或设置数据格式操作,不能 


打开文件,或改变屏幕显示样式 






7.明确参数类型 






在前面的部分,你学习了函数根据它们自变量传递的值进行计算,当你声明函数时,你将参数名称 


列在一对括号里面。参数名称就像变量一样,每个参数名称在函数调用时,引用你提供的数值。当 


子程序调用函数过程时,它以变量形式传递参数。一旦函数做点什么,它就将结果赋给函数名称。 


注意,函数过程的名称当作变量来使用。 


象变量一样,函数也有类型,函数的结果可以是字符串型,整型,长整型,等。要明确你函数的结 


果类型,只有在函数声明行后添加关键字As和你想要的类型即可。例如: 






Function MultiplyIt(num1, num2) As Integer 


如果你不明确数据类型,VB将把你的函数结果设置为默认类型(Variant数据类型)。当你明确你的 


函数结果的数据类型时,就象你明确变量的数据类型那样有一些好处,你的程序将更有效地使用内 


存,因此它运行得也更快些。 


我们来看看这个例子,尽管其参数在主调过程声明的是单精度浮点型,但是函数仍然返回整型数据: 


1. 在工程MyFunctions (Chap04.xls)里添加一个新模块,重命名为Sample3 


2. 激活模块Sample3并且输入子程序HowMuch,如下所示: 


Sub HowMuch() 


    Dim num1 As Single 


    Dim num2 As Single 


    Dim result As Single 


    num1 = 45.33 


    num2 = 19.24 


    result = MultiplyIt(num1, num2) 


    MsgBox result 


End Sub 


3. 在子程序HowMuch下面输入下列函数过程: 






Function MultiplyIt(num1,num2) As Integer 


    MultiplyIt = num1 * num2 


End Function 


因为储存于变量num1和num2的数值不是整数,要确保它们相乘后的结果为整数,你就得将函数结果 


设置为整型。如果你不给函数MultiplyIt的结果设置数据类型,过程HowMuch将会将结果按变量 


result声明的数据类型显示,相乘的结果将是872.1492,而不是872。 


你可以在每次运行该过程时,提供它们不同的数值,来使得该函数更有用,你可以使用InputBox 


函数来输入 数据,而不 拘泥于程序 代码给定的 数值。你自 己可以依照 前面章节中 的子程序 


EnterText,花几分钟来修改过程HowMuch。 






                                    87 




----------------------- Page 104-----------------------


8.按地址和按值传递参数 






在一些过程中,当你将参数作为变量传递时,VB可能突然改变该变量的数值。要确保该被调函数不 


改变传递的参数值,你应该在函数声明行在参数名称之前加上关键字ByVal。我们来看看这个例子: 


1. 在工程MyFunctions (Chap04.xls)里添加一新模块,命名为Sample4 


2. 激活模块Sample4并输入下列代码: 


Sub ThreeNumbers() 


    Dim num1 As Integer, num2 As Integer, num3 As Integer 






    num1 = 10 


    num2 = 20 


    num3 = 30 


    MsgBox MyAverage(num1,num2,num3) 


    MsgBox num1 


    MsgBox num2 


    MsgBox num3 


End Sub 


Function MyAverage(ByVal num1, ByVal num2, ByVal num3) 






    num1 = num1 + 1 


    MyAverage = (num1 + num2 + num3) / 3 






End Function 


使用关键字ByVal在参数名称前,可以防止函数改变参数值。子程序ThreeNumbers给三个变量赋值, 


再调用函数MyAverage来计算,最后计算该三个变量的平均值。函数的参数就是变量num1,num2和 


num3。注意,所有变量的前面都有关键字ByVal。同时,注意,在计算均值之前,函数MyAverage 


改变了变量num1的值,在函数内部,变量num1等于11(10+1),因此,当函数将计算的均值传递给 


过程ThreeNumbers时,函数MsgBox显示的结果是20.3333333333333而不是期望的20,接下来的三个 


函数显示每个变量的内容,变量储存的内容和它们开始被赋的值一致——10,20,30。 


如果你在函数声明行忽略了参数num1前面的关键字ByVal,结果会怎样呢?函数的结果仍然相同, 


但是函数MsgBox显示的变量num1的内容现在是11了。函数MyAverage不但返回了出乎意料的结果 


(20.3333333333333而非20),而且改变了储存在变量num1里的原始数值。要避免VB永久地改变提 


供给函数的数值,就得使用关键字ByVal。 


技巧4-9 了解你的关键字:ByRef和ByVal 


因为每个要传递给函数过程(或子程序)的变量,都可能在接收时改变数值,所以知道如何来保护 


变量的原始数值是非常重要的。VB有两个关键字,提供或者否认改变变量内容的允许——ByRef和 


ByVal。VB默认地按地址(关键字ByRef)给函数过程(或子程序)传递信息,引用函数被调用时, 


函数参数明确的数据。因此,如果函数改变了参数值,原始的数值就被改变了。如果你在函数 


MyAverage声明参数num1的前面忽略了关键字ByVal时,你就会得到这种结果。如果你想要函数过程 


改变原始数值,你不必专门在参数前加关键字ByRef,因为,变量数值的传递默认就是ByRef。当你 


在参数名称前使用关键字ByVal时,VB按值传递参数,这意味着VB复制一份原始数据,然后将复制 


值传递给函数,如果函数改变了参数的数值的话,原始数据依然不会变——只有复制值变化。这就 


是为什么函数MyAverage改变了变量num1的数值,而它的原始值还保持不变。 






9.使用可选的参数 






有时候,你也许要给函数提供额外的参数,例如,你有一个计算每个人膳食的函数。然而,有时你 


不希望函数进行相同的计算。在参数名称前面加上关键字Optional可以指明该参数不是必须的。可 


选参数在必须的参数之后,列在参数清单的最后;可选参数总是Variant数据类型,这意味着你不 


能使用关键字As来明确可选参数的类型。在前面部分,你创建了一个计算三个数值的平均值的函数, 


假设,你有时只想要计算两个数的均值,你就可以将第三个参数设置为可选的。为了不破坏原来的 


函数MyAverage,我们来创建一个新的函数Avg,来计算两个或三个数字的均值: 


1. 在工程MyFunctions (Chap04.xls)里添加一新模块,命名为Sample5 


2. 激活模块Sample5并且输入下列函数: 


Function Avg(num1, num2, Optional num3) 






                                   88 




----------------------- Page 105-----------------------


    Dim totalNums As Integer 


    totalNums = 3 


    If IsMissing(num3) Then 


        num3 = 0 


        totalNums = totalNums –1 


    End If 


    Avg = (num1+num2+num3)/totalNums 


End Function 


3. 现在来从立即窗口调用该函数: 


?Avg(2,3) 


一旦你按下回车,VB就显示结果:2.5 


?Avg(2,3,5) 


这次结果为:3.3333333333333 


你已经看到,函数Avg允许你计算两个或三个数字的平均值,你可以决定计算几个值的平均值。当 


你在立即窗口开始输入函数的参数时,VB将可选的参数显示在方括号里(译者:方括号里的参数表 


示是可选的) 


我们花几分钟来分析一下函数Avg。该函数最多可以用三个参数;参数num1和num2是必须的,而第 


三个参数num3是可选的。注意,可选参数以关键字Optional开头,可选参数列在参数清单的后面。 


因为参数num1,num2和num3的类型都没有声明,VB对待它们为Variant。 


函数内部,变量totalNums声明为整型,并且初始赋值为3。因为该函数必须能够处理两个或三个数 


字的平均值计算,有关很方便的内置函数IsMissing在检查参数的个数。如果第三个参数没有提供, 


函数IsMissing的值为0,同时变量totalNums的值被减去1,因此如果没有可选参数,totalNums为2。 


接下来的代码根据提供的数据计算平均值,并且将结果传递到函数名称。 


函数IsMissing用来检测可选参数是否提供,如果第三个参数没有提供,那么该函数返回逻辑值 


True,如果提供了第三个参数时,则返回False。在这里,函数IsMissing是和一个做判断的语句 


If…Then一起使用的(参见第五章有关该语句和VBA中其它判断语句信息)。如果没有参数num3 


(IsMissing),那么(Then)VB将num3设置为0,并且将变量totalNums减去1(totalNums = totalNums 


– 1)。你还能使用别的方法来运行函数Avg吗?使用你自己的方法在工作表里运行该函数,确保你 


使用两个和三个参数来运行该函数。 


技巧4-10 测试函数过程 


可以编写一个子程序调用自定义函数,并且显示它的结果,看它是否能得到设计结果。除此之外, 


该子过程还应该能显示参数的原始数据,这样,你才能很快知道参数数值是否改变了。如果该函数 


使用了可选参数,你也需要检查不使用可选参数时候的情况。 






10.定位内置函数 






VBA自带了很多内置函数,可以在在线帮助里很容易地找到这些函数。在VB编辑器窗口选择“帮助” 


-“Microsoft Visual Basic帮助”可以访问所有VBA函数按字母顺序排序的清单,然后点击“函 


数”, 


例如,以MsgBox或InputBox函数为例。一个程序好的功能之一就是要与用户互动,当你使用Excel 


时,你通过多种对话框与该应用程序交流,当你犯错的时候,对话框会弹出来,并且告诉你有错误。 


当你编写你自己的程序时,你也可以将出乎意料的错误或某个计算的结果通知用户,你可以使用函 


数MsgBox帮助你做这些。到目前为止,你只是看到了这个函数的一些简单应用,在下面的部分,你 


将了解如何控制你信息的外观;你也将学习如何使用函数InputBox从用户获得信息。在我们详细讨 


论这些函数之前,我们来看一个VBA函数,在你已经很熟悉变量和它们的类型的时候,它对你特别 


有用处。 


VB有个VarType函数,它返回一个值变量类型的整数。图4-4例显示了函数VarType的语法和它返回 


的值。 






                                    89 




----------------------- Page 106-----------------------


图4-4 使用内置函数VarType,你可以判别变量的类型(译者:本截图与2002版本有区别) 


现在,看看如何在立即窗口里使用这个函数: 


1. 打开立即窗口 


2. 输入下列给变量赋值的语句 


age = 18 


birthdate = #1/1/1981# 


firstName = "John" 


3. 现在询问VB每个变量的数据类型是什么: 


?varType(age) 


你按下回车时,VB返回2,如图4-4所示,数字2代表整数类型。 


?varType(birthdate) 


VB返回7代表日期。如果你在变量名称上犯了个小错误(比如说,你输入了birthday而不是 


birthdate),VB将返回0。 


?varType(firstName) 


VB告诉你变量firstName的数据是字符串(8)。 






11.使用 MsgBox 函数 






你目前使用的MsgBox函数局限于给用户用一个简单的,一个按钮的对话框显示信息。你点击确定按 






钮或者回车来关闭该信息框。要创建一个简单的信息框,只要在MsgBox函数名称后面带上一个用引 


号包括起来的文本就可以了。换句话说,要显示信息“过程已完成”,你应该准备下列语句: 


MsgBox "过程已完成" ‘(注意,英文状态的引号) 


你可以将它输入立即窗口,快速地测试上面的指令,当你输入完这条指令并且回车后,VB就显示如 






                                      90 




----------------------- Page 107-----------------------


图4-5的信息框。 






图4-5 将文本作为MsgBox函数的参数,来给用户显示信息 


MsgBox函数允许你使用其它参数,使你可能决定可用的按钮数目,或者将默认的信息框的标题 


(Microsoft Excel)改为你自己的标题。也可以设置你自己的帮助主题。MsgBox的语法如下: 


MsgBox (prompt [, buttons] [, title], [, helpfile, context]) 






注意,MsgBox函数有五个参数,只有第一个,Prompt(提示),是必须的;这些列在方括号里面的 


参数都是可选的。当你在提示参数输入一个非常长的文本时,VB决定如何断句,使文本适合信息框 


大小。我们在立即窗口里来做些练习,看不同的文本格式技巧: 


1. 在立即窗口输入以下指令,确保在一行里输入整个文本,回车 


MsgBox "All done. Now open ""Chap04.xls"" and place an empty disk in the diskette drive. 






The following procedure will copy this file to the disk." 


一旦回车,VB显示信息框,如图4-6 






图4-6 如果你设置一下文本格式,长信息看上去将会更吸引人 


如果你遇到编译错误,可以点击确定,然后确定文件名用双引号括起来——““Chap04.xls””。 


当你的信息文本特别长时,你可以使用VBA函数Chr将它分割为好几行。Chr函数需要你跟参数,这 


个参数是0到255之间的数字,它返回这个数字代表的字符。例如Chr(13)返回的是回车(这和按下 


回车键相同),以及Chr(10)返回换行字符(这在文本行之间添加空行很有用)。 


2. 将上面的指令修改为下述方式: 


MsgBox "All done." & Chr(13) & "Now open ""Chap04.xls"" and place" & Chr(13) & "an empty 






disk in the diskette drive." & Chr(13) & "The following procedure will copy this file to 






the disk." 






图4-7 通过使用Chr(13)可以将长文本分割成几行 


你必须将每段文本片断用引号括起来,内嵌在括号里面的文本(显示状态)需要再用一对括号来括 


起来,例如““Chap04.xls””。Chr(13)函数指明你希望开始新的一行的地方。字符串的连接字 


符(&)用来返回连接字符串的字符。 


在一行输入及其长的文本的时候,很容易失误。回想一下,VB有一个专门的线连续字符(下划线_) 


帮你将长VBA语句分割为几行,不幸的是,这个线连续符不能在立即窗口使用。 


3. 在工程MyFunctions (Chap04.xls)里添加一个新模块并命名为Sample6 


4. 激活模块Sample6并且输入如下所示的子程序MyMessage,确保在每个线连续符前面加个空格: 


Sub MyMessage() 


    MsgBox "All done." & Chr(13) _ 






                                    91 




----------------------- Page 108-----------------------


    & "Now open ""Chap04.xls"" and place" & Chr(13) _ 






    & "an empty disk in the diskette drive." & Chr(13) _ 






    & "The following procedure will copy this file to the disk." 


End Sub 


你运行过程MyMessage时,VB显示如图4-7一样的信息。正如你看到的,在几行输入的文本更具可 


读性,而且代码更容易维护。你可以在文本行之间添加一下空白行,来增加信息的可读性。使用 


Chr(13)或two Chr(10)函数就可以做到,如下列步骤所述。 


5. 输入下面的MyMessage2过程: 


Sub MyMessage2() 






    MsgBox "All done." & Chr(10) & Chr(10) _ 


    & "Now open ""Chap04.xls"" and place" & Chr(13) _ 






    & "an empty disk in the diskette drive." & Chr(13)& Chr(13) _ 


    & "The following procedure will copy this file to the disk." 


End Sub 


图4-8显示了MyMessage2过程产生的信息框。 






图4-8 你可以通过在文本行之间添加空行增加信息的可读性 


既然你已经掌握了文本的格式技术,那么我们就来仔细地看看MsgBox函数的下一个参数吧。尽管按 


钮参数时可选的,但是它的使用还是很频繁的。这个按钮参数明确多少个按钮,并且是什么样的按 


钮你想要出现了信息框上,这个参数可以是个常量(参见表4-1),也可以是个数字。如果你忽略 


这个参数,结果辛苦只会有一个“确定”按钮,正如你在前面的例子里看到的那样。 


表4-1 MsgBox按钮参数的设置 


常量                      值             描述 


按钮设置 


vbOKOnly                0             仅显示确定按钮,这是默认值 


vbOKCancel              1             显示确定和取消按钮 


vbAbortRetryIgnore      2             显示终止,重试和忽略按钮 


vbYesNoCancel           3             显示是,否和取消按钮 


vbYesNo                 4             显示是和否按钮 


vbRetryCancel           5             显示重试和取消按钮 


图标设置 


vbCritical              16            显示重要信息图标 


vbQuestion              32            显示问号图标 


vbExclamation           48            显示警告信息图标 


vbInformation           64            显示信息图标 


默认按钮设置 


vbDefaultButton1        0             第一个按钮是缺省值 


vbDefaultButton2        256           第二个按钮是缺省值 


vbDefaultButton3        512           第三个按钮是缺省值 


vbDefaultButton4        768           第四个按钮是缺省值 


信息框形式 


vbApplicationModal      0             应用程序强制返回;应用程序一直被挂起,直到 






                                    92 




----------------------- Page 109-----------------------


                                   用户对消息框作出响应才继续工作。 


vbSystemModal         4096         系统强制返回;全部应用程序都被挂起,直到用 


                                   户对消息框作出响应才继续工作。 


MsgBox显示的其它设置 


vbMsgBoxHelpButton    16384        将Help按钮添加到消息框 


vbMsgBoxSetForeground 65536        指定消息框窗口作为前景窗口 


vbMsgBoxRight         524288       文本为右对齐 


vbMsgBoxRtlReading    1048576      指定文本应为在希伯来和阿拉伯语系统中的从右 


                                   到左显示 






你什么时候应该使用按钮参数呢?假设你要用户对一个问题回到“是”或“否”,你的信息框就需 


要两个按钮,当信息框有一个以上的按钮时,就需要将其中一个设置为缺省值,当用户回车的时候, 


这个默认的按钮就会自动地被选上。 


因为,你可以显示各种各样的信息(重要,警告,信息),所以,你需要通过按钮参数设置图形代 


表(图标)来指明信息的重要性。 


除了信息类型之外,按钮参数还可以设置是否用户必须先关闭该信息框才能切换到另外的应用程 


序。很多情况下,用户需要在对信息框的问题做出反应之前,切换到另外的程序或者进行另外的操 


作。如果这个信息框是应用程序模式(vbApplication Modal)的话,用户必须先关闭该信息框后 


才能继续使用你的应用程序。另一方面,如果你想要在用户对信息框响应之前,将所有应用程序挂 


起,那么你必须在按钮参数里加上系统强制返回设置(vbSystemModal)。按钮参数的设置分为五组: 


按钮设置,图标设置,默认按钮设置,信息框形式和其它的MsgBox显示设置(参见图4-1)。每组 


设置里面只能选一个加入按钮参数里面。你可以将每种需要的设置加和起来,来设置按钮参数,例 


如,要显示一个带两个按钮(“是”和“否”),问号图标以及将“否”按钮设置为缺省值的信息框, 


你可以在表4-1里查找相应的值并且加和起来,你应该得到292(4+32+256)。你可以在立即窗口里 


面输入下列代码,快速查看使用该计算的按钮参数的信息框: 


MsgBox "Do you want to proceed?", 292 


下面显示的就是信息框结果。当你直接使用加和起来的值作为参数时,你的程序可读性就不高了, 


因为没有参考索引表格供你检查292背后的意思。要改善你信息框函数的可读性,最好使用常量, 


而不要使用它们的值,例如,在立即窗口输入下列修改后的语句: 






MsgBox "Do you want to proceed?", vbYesNo + vbQuestion + vbDefaultButton2 


上面的语句得到如图4-9所示的相同结果。 






图4-9 你可以使用可选的按钮参数来确定信息框上的按钮个数 


下面的例子示范如何在VB过程里使用按钮参数: 


1. 在工程MyFunctions (Chap04.xls)里添加一新模块,并命名为Sample7 


2. 激活Sample7模块,并且输入如下子程序MsgYesNo: 


Sub MsgYesNo() 


    Dim question As String 


    Dim myButtons As Integer 


    question = "是否要打开一个新工作簿?" 






    myButtons = vbYesNo + vbQuestion + vbDefaultButton2 


    MsgBox question, myButtons 


End Sub 


在 上 面 的 子 程 序 里 , 变 量 question 储 存 了 你 的 信 息 文 本 , 而 按 钮 参 数 的 设 


置 则 储 存 于 变 量 


myButtons。除了使用常量名称之外,你还可以使用它们的值,例如下面的: 


                                  93 




----------------------- Page 110-----------------------


myButtons = 4 + 32 + 256 


但是,明确了按钮常数的常量名称的话,你可以使你的程序对你自己以及将来可能要使用该程序的 


人来说更容易理解。变量question和myButtons用作MsgBox函数的参数。运行该程序后,你将看到 


如图4-9所示的结果。注意,现在按钮“否”是被选中的,它是该对话框的默认按钮,如果你按下 


回车,Excel将该信息框从屏幕上移除,因为MsgBox函数后面没有任何指令,所以,不会发生其它 


操作。将默认按钮换成vbDefaultButton1设置,可以更改默认按钮。 


MsgBox函数的第三个参数是标题,虽然这也是个可选参数,但是它很方便,因为当你忽略它们(默 


认为Microsoft Excel)时,就不能给程序提供可视提示。你可以使用这个参数,将标题栏设置为 


你想要的任何文字。假设你要过程MsgYesNo显示标题为“新工作簿”,下面的过程MsgYesNo2示范如 


何使用标题参数: 


Sub MsgYesNo2() 


    Dim question As String 


    Dim myButtons As Integer 


    Dim myTitle As String 






    question = "Do you want to open a new workbook?" 


    myButtons = vbYesNo + vbQuestion + vbDefaultButton2 






    myTitle = "New workbook" 


    MsgBox question, myButtons, myTitle 






End Sub 


标题参数文本储存于变量myTitle。如果你没有明确标题参数的内容,VB将默认显示为“Microsoft 


Excel”。注意,参数是基于MsgBox函数决定的顺序列出的,如果你要按你自己的顺序列出这些参数 


的话,你就必须将参数名称一起写出,例如: 


MsgBox title:=myTitle, prompt:=question, buttons:=myButtons 






后面两个参数——帮助文件(helpfile)和上下文(context)——经常为那些对Windows环境下的 


帮助文件很熟悉的程序员使用。参数helpfile指明某个包含你要显示给用户的附加信息的具体帮助 


文件的名称,当你明确了这个参数后,Help按钮就会在信息框上显示出来。当你使用helpfile参数 


时,你同时也使用context参数。这个参数表明在帮助文件里你要显示的那个帮助主题。假设 


Help.hlp是你创建的帮助文件,55是你要使用的帮助主题,你可以按照如下指令来显示这些信息于 


信息框上: 


MsgBox title:=mytitle, _ 


     prompt:=question _ 


     buttons:=mybuttons _ 


     helpFile:= "HelpX.hlp", _ 


     context:=55 


上面只是一条VBA语句,使用连接符打断为好几行。 






12.MsgBox 函数的运行值 






当你显示只有一个按钮的信息框时,可以点击确定按钮或者回车键将信息框从屏幕上移除,然而, 


当信息框有两个或以上的按钮时,你的程序需要知道按的是哪个按钮。你可以将信息框结果储存在 


一个变量上来实现。表4-2 显示了MsgBox函数返回值。 


表4-2 MsgBox函数返回值 


选择的按钮                常数            值 


OK(确定)               VbOK          1 


Cancel(取消)           vbCancel      2 


Abort(终止)            vbAbort       3 


Retry(重试)            vbRetry       4 


Ignore(忽略)           vbIgnore      5 


Yes(是)               vbYes         6 


No(否)                vbNo          7 






                                    94 




----------------------- Page 111-----------------------


MsgYesNo3过程是MsgYesNo2过程修改后的版本,示范如何确定用户按下的是哪个按钮: 


Sub MsgYesNo3() 


      Dim question As String 


      Dim myButtons As Integer 


      Dim myTitle As String 


      Dim myChoice As Integer 


      question = "Do you want to open a new workbook?" 






      myButtons = vbYesNo + vbQuestion + vbDefaultButton2 


      myTitle = "New workbook" 






      myChoice = MsgBox(question, myButtons, myTitle) 


      MsgBox myChoice 


End Sub 


在上面的过程里,你将MsgBox函数的结果赋给变量myChoice。注意,现在,MsgBox函数的参数列在 


括号里面: 






myChoice = MsgBox(question, myButtons, myTitle) 


当你运行MsgYesNo3时,出现带有两个按钮的信息框,当你点击“是”时,MsgBox myChoice将显示 


数字6;当点击“否”则得到数字7。你将在第五章里面学习如果让程序根据按钮的选择进行不同的 


任务。 


技巧4-11 MsgBox函数——使用还是不使用括号? 


当你需要使用MsgBox函数返回的结果时,需要使用括号将该函数的参数包括起来。不使用括号,意 


味着你告诉VB你将忽略该函数的结果。当MsgBox函数包含两个或以上的按钮时,你很可能想要使用 


该函数的结果。 






13.使用 InputBox 函数 






InputBox函数显示一个信息提示用户输入数据,这个对话框有两个按钮——“确定”和“取消”, 


当你点击确定时,InputBox函数返回用户输入在信息框里的信息;当你点击取消时,函数则返回空 


字符串(” ”)。InputBox函数的语法显示如下: 


InputBox(prompt [, title] [, default] [, xpos] [, ypos] _ [, helpfile, context]) 


第一个参数,prompt,是你想要显示在对话框上的信息,你可以使用函数Chr(13)或Chr(10)将长文 


本打断为几行(参见本章中使用MsgBox函数的例子)。剩下所有的参数都是可选的。 


第二个参数,title,让你改变对话框的默认标题,默认的标题是Mictosoft Excel。 


InputBox函数的第三个参数,default,让你在文本框里显示一个默认值,如果你忽略这个参数的 


话,显示的将是空白编辑框。 


接下来的两个参数,xpos和ypos,允许你设置该对话框在屏幕上出现的位置,如果你忽略这两个参 


数,对话框就会出现了当前窗口的中央,xpos参数决定对话框在屏幕上从左起的水平位置,忽略它 


时,对话框显示在水平中央,而ypos参数决定对话框在屏幕从上而下的竖直位置,忽略它,对话框 


就在竖直大约三分之一的位置。xpos和ypos都使用一个叫twips的专门单位衡量,1twip大约等于 


0.0007英寸。 


最后两个参数,helpfile和context,和在本章前期讨论的MsgBox函数相应的参数使用方法一样。 


现在你知道了InputBox参数的意义了,我们来看看这个函数的使用示例: 


1. 在MyFunctions (Chap04.xls)工程里添加一个新模块,重命名为Sample8 


2. 激活Sample8模块,并且输入下列子程序: 


Sub Informant() 






      InputBox prompt:="Enter your place of birth:" & Chr(13) _ 


            & " (e.g., Boston, Great Falls, etc.) " 






End Sub 


上面的过程显示一个带两个按钮的对话框,输入提示显示在两行里。象MsgBox函数一样,如果你想 


要使用用户输入的数据,那么你应该使用一个变量来储存该对话框结果。下面显示的子程序 


Informant2将InputBox函数的结果赋值给变量town: 






                                     95 




----------------------- Page 112-----------------------


图4-10 Informant子程序产生的对话框 


Sub Informant2() 


      Dim myPrompt As String 


      Dim town As String 


      Const myTitle = "Enter data" 






      myPrompt = "Enter your place of birth:" & Chr(13) _ 


             & "(e.g., Boston, Great Falls, etc.)" 






      town = InputBox(myPrompt, myTitle) 


      MsgBox "You were born in " & town & ".", , "Your response" 






End Sub 


注意,这次,InputBox函数的参数列在了括号中间。如果你需要在稍后的程序中需要使用InputBox 


函数的结果,那么括号是必须的。Informant2子程序使用常数来确定显示在对话框标题上的文本。 


因为,这个值在过程执行过程中从始至终都是保持不变的,所以,可以将对话框的标题声明为一个 


常量,然而,如果你愿意,你也可以使用一变量。 


当你运行使用了InputBox的过程时,使用该函数的对话框总是出现在屏幕的同一位置,你可以按前 


面解释的那样,提供xpos和ypos参数来改变对话框的位置。 


3. 修改过程Informant2中的InputBox函数,让对话框显示在屏幕的左上角,例如: 


town = InputBox(myPrompt, myTitle, , 1, 200) 


注意,参数myTitle后面紧跟两个逗号,第二个逗号是忽略掉的默认值参数。下面两个参数决定对 


话框的水平和竖直位置。如果你忽略了参数myTitle后面的第二个逗号,VB将会使用数字1作为默认 


值 。 如 果 你 使 用 了 参 数 名 称 的 话 ,( 例 如 , prompt:=myPrompt, title:=myTitle, 


xpos:=1, 


ypos:=200),你就不必记住在每个忽略了参数的地方加逗号了。 


如果你输入了一个数字,而不是一个城镇的名称,后果会怎样?因为,用户经常会在对话框里输入 


错误的数据,所以,你的程序必须验证用户输入的数据是否可以在将来的数据操作里使用。InputBox 


函数本身并没有提供验证数据的工具,要验证用户的输入,你必须使用其它的VBA指令,这将在下 


章里讲述。 






14.数据类型转变 






InputBox函数的结果总是字符串,如果用户输入的是个数字,用户输入的字符串值必须转换成为数 


字值之后,才能用于你程序里的数学计算。VB转换数据类型轻而易举,不过,在早期的Excel版本 


里,这是不可能的。 


1. 激活模块Sample8,并输入以下过程AddTwoNums: 


Sub AddTwoNums() 


      Dim myPrompt As String 


      Dim value1 As String 


      Const myTitle = "Enter data" 


      Dim mySum As Single 


      myPrompt = "Enter a number:" 






      value1 = InputBox(myPrompt, myTitle, 0) 


      mySum = value1 + 2 


      MsgBox mySum & " (" & value1 & " + 2)" 






End Sub 






                                      96 




----------------------- Page 113-----------------------


图4-11 要给用户提示数据的确切类型,你可以在编辑框里提供一个默认值 


上面的程序显示如图4-11所示的对话框。注意,这个对话框使用了两个专门的功能,InputBox函 


数的可选参数标题和默认值。该对话框显示了有常量myTitle确定的文本字符串作为标题,而不是 


默认的“Microsoft Excel”。在编辑框里面的0提示用户输入数字,而不能输入文本。一旦用户输 


入了数据并点击确定时,用户的输入就被赋值给了变量value1 


value1 = InputBox(myPrompt, myTitle, 0) 


变量value1的数据类型是字符串,你可以在上面指令的下面加上如下语句,快速地查看它的数据类 


型: 


MsgBox varType(value1) 


当VB运行上面的代码时,将显示信息-数字8,你可以在本章的图4-4里查看该数字代表字符串类 


型。 


技巧4-12 定义常量 


你可以将标题文本赋值到一个常量上,以确保某个VBA程序里所有的标题栏都显示相同的 文本。依 


照这个技巧,你可以在多次输入某标题文本时节省时间。 


技巧4-13 避免类型不匹配错误 


如果你试图在Excel的早期版本里(2000以前版本)运行AddTwoNums过程,当VB试图执行下列代码 


行时,你将得到类型不匹配的错误: 


mysum = value1 + 2 


使用内置函数CSng将储存于value1的字符串转换为一个单精度浮点类型的数字,可以避免类型不匹 


配错误,代码写成: 


mysum = CSng(value1) + 2 


下一行,mySum = value1 + 2,在用户输入的数据上加上2,并且将计算结果赋值给变量mySum。因 


为变量value1的数据类型时字符串,在使用它计算之前,VB在后台进行数据类型的转换,VB知道转 


换的需要。没有它,两种不兼容的数据类型(文本和数字)将会产生类型不匹配错误。程序最后是 


一个MsgBox函数,显示计算的结果已经给用户显示总数是如何组成的。 






15.使用 InputBox 方法 






除了InputBox函数之外,还有InputBox方法,如果你激活对象浏览器,然后搜索“inputbox”,VB 


将显示两个InputBox——一种为Excel库,另一种为VBA库(见图4-12)。InputBox方法在Excel库 


里面可用,它的语法和本章前面讲的InputBox函数的语法有轻微差别,它的语法为: 


expression.InputBox(Prompt, [Title],  [Default],  [Left],  [Top],  [HelpFile], 


[HelpContextID], [Type] ) 


所有方括号里面的参数都是可选的。Prompt(提示)参数是显示于对话框上的信息;Title是对话 


框的标题;而Default是对话框上文本框里的初始值。Left和Top参数是明确对话框在屏幕上的位置。 


这 些 参 数 的 输 入 值 的 单 位 是 Point ( 1/72 英 寸 )。 当 用 户 点 击 帮 助 按 钮 时 


 , 参 数 HelpFile 和 


HelpContextID明确帮助文件名称以及某个明确的帮助主题。InputBox方法的最后一个参数—— 


Type(类型)明确返回的数据类型。如果你忽略这个参数,InputBox方法将会返回文本格式。类型 


参数的值列在表4-3里。 






                                  97 




----------------------- Page 114-----------------------


图4-12 别忘记使用对象浏览器来搜索VB函数和方法 


表4-3 InputBox方法返回的数据类型 


值                         返回的数据类型 


0                         公式 


1                         数字 


2                         字符串(文本) 


4                         逻辑值(True或False) 


8                         单元格引用,作为一个Range对象 


16                        错误值,例如#N/A 


64                        数组 






如果你使用3作为Type参数的话,用户将既可以输入一个数字也可以输入一个文本。这个值是将1 


(数字)和2(字符串)加和而得到的。InputBox方法很适合那些需要用户选择工作表单元格范围 


的VBA程序。 


1. 关闭对象浏览器,如果你已经打开了的话 


2. 在模块Sample8里面,输入下列过程WhatRange: 


Sub WhatRange() 


      Dim newRange As Range 


      Dim tellMe As String 


      tellMe = "Use the mouse to select a range:" 






      Set newRange = Application.InputBox(prompt:=tellMe, _ 


            Title:="Range to format", _ 


            Type:=8) 


      newRange.NumberFormat = "0.00" 


      newRange.Select 


End Sub 


过程WhatRange开始于一对象变量的声明——newRange。试回想一下第三章,对象变量指向数据的 


地址。用户选择的单元格被赋值给对象变量newRange。注意变量名称前面的关键字Set: 


Set newRange = Application.InputBox(prompt:=tellMe, _ 






  Title:="Range to format", _ 


  Type:=8) 


类型参数(Type:=8)使用户能够选择任何单元格区域。当用户选中单元格区域时,下句指令: 






                                     98 




----------------------- Page 115-----------------------


newRange.NumberFormat = "0.00" 


改变所选单元格的格式。最后一句选择用户加亮的区域。 


3. 运行过程WhatRange。VB显示一个对话框,提示用户在工作表里选择一个单元格区域。 


4. 使用鼠标选择你要的单元格,当鼠标在单元格上拖动时,VB就会将选择的区域引用到对话框的 


   编辑框里面。 






图4-13 使用Excel的InputBox方法,你可以从用户处获得区域地址 


5. 你选择了单元格后,点击对话框上的确定按钮,被选择的区域就已经设置好格式了。要检查是 


   否按你的意思设置了,你可以在该区域的任意单元格里输入一个整数,这个数字应该显示为两 


   位小数。 


6. 重新运行该过程,并且当出现对话框时,点击取消按钮。如果你在选择了一个单元格或者一个 


   区域后点击确定按钮,过程WhatRange将工作正常。不幸地是,当你点击取消按钮或Esc按钮, 


   VB将显示一错误信息——“要求对象”。当你点击错误对话框上的调试按钮,VB就会加亮导致 


   错误的代码行。因为你不希望在取消对话框时选择任何单元格,所以你必须想个法子忽略VB 


   显示的这个错误。使用一个专门的语句,On Error GoTo 标志,你就可以绕过错误的发生。该 


   指令的语法如下: 


   On Error GoTo 标志 


   这个指令应该放在变量声明行的下面。标志可以是除了VB关键字之外的任何你想要的词语。如 


   果错误发生时,VB就会直接跳到该特别的标志,如下面步骤8所示。 


7. 选择“运行”-“重新设置”以取消正在运行的程序。 


8. 将过程WhatRange修改为如下所示WhatRange2: 


    Sub WhatRange2() 


      Dim newRange As Range 


      Dim tellMe As String 


      On Error GoTo VeryEnd 






      tellMe = "Use the mouse to select a range:" 






                                    99 




----------------------- Page 116-----------------------


      Set newRange = Application.InputBox(prompt:=tellMe, _ 






        Title:="Range to format", _ 


        Type:=8) 


      newRange.NumberFormat = "0.00" 


      newRange.Select 


    VeryEnd: 


    End Sub 


9. 运行程序WhatRange2,一旦出现对话框时就点击取消按钮。注意,这次程序没有产生错误。当 


   VB遭遇错误时,就会跳到位于程序结尾处的标志VeryEnd。位于错误和标志VeryEnd之间的语句 


   被忽略了(原文不当:The statements placed between On Error Goto VeryEnd and the VeryEnd 


   label are ignored)。你将在第十三章里面找到更多的诱捕VBA程序里错误的例子。 


技巧4-14 子程序和函数:你应该使用哪个? 


创建子程序的时候: 


  需要执行一些动作 


  需要获取用户信息 


  需要在屏幕上显示信息 


创建函数的时候: 


  需要不只一次的做一些简单的计算 


  需要做复杂的计算 


  需要不只一次地调用相同的指令块 


  需要检查某些表达正确与否 






16.使用主过程和子过程 






当你大VBA程序得越来越大,要很好地维护这么多的代码行是很困难的。要让你的程序容易编写、 


理解和改变,你就应该使用井井有条的结构化程序。如何创建结构化程序?你只要简单地将大问题 


分成一些可以同时执行的小问题就行。在VBA中,你可以通过创建一个主过程和一个或多个子过程 


来实现它。因为主过程和子过程都是子程序,所以你都可以用关键字Sub将它们声明。主过程可以 


调用所需的子过程,并且将参数传递给它们。它也可以调用函数。下面的例子显示过程AboutUser。 


该过程要求用户姓和名,并且将姓和名从全名中分离出来。最后的语句显示用户的姓,随后是逗号 


和名。你再读下去,该过程将被分割成几个任务,以示范使用主过程,子过程和函数的概念。 


Sub AboutUser() 


  Dim fullName As String 


  Dim firstName As String 


  Dim lastName As String 


  Dim space As Integer 


  'get input from user 从用户获取信息 






  fullName = InputBox("Enter first and last name:") 


  'get first and last name strings 获得姓和名字符串 


  space = InStr(fullName, " ") 


  firstName = Left(fullName, space – 1) 


  lastName = Right(fullName, Len(fullName) – space) 


  'display last name, first name 显示姓和名 


  MsgBox lastName & ", " & firstName 


End Sub 


过程AboutUser可以分割为一些细小的任务。第一个任务便是获取用户的全名;下一个任务则需要 


你将用户提供的数据分割为两个字符串:姓和名,这些任务可以交给不同的函数(例如:GetLast 


和GetFirst);最后的任务是显示重新排列的姓名字符串信息。既然你已经知道了你应该注重于哪 


些任务,我们现在就来看看如何完成每个任务。 


1. 在你当前的VBA工程里面添加一个模块,并重命名为Sample9 


2. 在Sample9模块窗口里面输入下列过程AboutUserMaster: 






                                   100 




----------------------- Page 117-----------------------


Sub AboutUserMaster() 






  Dim first As String, last As String, full As String 






  Call GetUserName(full) 


  first = GetFirst(full) 


  last = GetLast(full) 


  Call DisplayLastFirst(first, last) 


End Sub 


上面显示的主过程通过调用适当的子程序和函数来控制程序的主流程。该主过程以变量生命开始, 


第一条语句Call GetUserName (full)调用子过程GetUserName(见第三步)并且传递给一参数—— 


变量full的内容。 


因为变量在执行调用语句之前没有赋与任何值,所以它的值是一个空字符串(“ ”)。注意,子过程 


的名称在Call之后。尽管你在调用过程时并没有要求使用关键字Call,但是,你在调用一个需要参 


数的过程时就必须使用它。参数列表必须包括在括号里面。 


3. 输入下面的GetUserName子程序: 






Sub GetUserName(fullName As String) 


  fullName = InputBox("Enter first and last name:") 






End Sub 


过程GetUserName示范了两个非常重要的VB编程概念:如何传递参数给一子程序以及如何将值从子 


程序传递回给主调过程。 


在主过程(见第二步)中,你调用了过程GetUserName,并且将其作为一参数传递:变量full。该 


变量被参数fullName接收,该参数子过程GetUserName的Sub语句里声明了。因为在VB调用子过程 


GetUserName的时候,变量full包含一空字符串,参数fullName同样也接收了这个空字符串。当VB 


显示对话框并且获得用户的姓名时,这个姓名将赋给参数fullName。赋给参数的值被传递回给子过 


程执行后的匹配参数。因此,当VB返回主过程时,变量full就回包含用户的姓名。 


传递给子过程的自变量将被其参数接收。注意,参数名称(fullName)后面紧跟着数据类型的声明 


(As String)。虽然,参数的数据类型必须和相匹配的自变量的数据类型一致,但是,不同的名称 


还是可以使用给一个自变量和它相应的参数。 


技巧4-15 自变量(Arguments)和参数(Parameters) 


  自变量是传递给一个子过程的变量,常量或表达式 


  参数则只是接收值并传递给子过程的变量 


4. 输入下述函数GetFirst: 


Function GetFirst(fullName As String) 


  Dim space As Integer 


  space = InStr(fullName, " ") 


  GetFirst = Left(fullName, space - 1) 






End Function 


主过程中的第二条语句(见第二步)first = GetFirst(full),将变量full的值传递给函数GetFirst。 


函数的参数fullName接收到该值。要从用户提供的数据里分出姓和名,你就必须找到姓和名中间的 


空格。因此,该函数的开头是当地变量space的声明,下条语句则使用VBA内置函数InStr返回字符 


串fullName里空格(“ ”)的位置。然后将获得的数字赋值给变量space。最后,Left函数用来提取 


字符串fullName从左到某特定个数(space -1)的字符。名的长度比储存在变量space的值少一个 


字符。函数的结果(用户的名)赋值给函数名。当VB返回主过程时,它就将结果放置于变量first。 


5. 输入下列函数GetLast: 


Function GetLast(fullName As String) 






  Dim space As Integer 


  space = InStr(fullName, " ") 


  GetLast = Right(fullName, Len(fullName) - space) 






End Function 


主过程里面的第三条语句(见第二步)last = GetLast(full),将变量full的值传递给函数GetLast。 


该函数的目的是提取用户提供的数据中的用户的姓。函数GetLast使用内置函数Len来计算字符串 






                                     101 




----------------------- Page 118-----------------------


fullName的总字符数。函数Right提取字符串fullName从右边某个特定字符开始(Len(fullName) – 


space)的字符。然后,获得的字符串赋值给函数名称,一旦返回主过程,它就储存于变量last。 


6. 输入下述子过程DisplayLastFirst: 


Sub DisplayLastFirst(firstName As String, lastName As String) 






  MsgBox lastName & ", " & firstName 


End Sub 


主 过 程 里 面 的 第 四 条 语 句 ( 见 第 二 步 ) Call DisplayLastFirst(first, last) , 


调 用 子 过 程 


DisplayLastFirst 并 且 将 两 个 自 变 量 : first 和 last 。 为 了 接 收 这 些 自 变 量 , 


子 过 程 


DisplayLastFirst和两个相匹配的参数(firstName和lastName)一起被声明了。回想我们前面说 


过,不同的名称可以用在自变量和相应的参数上。然后子过程DisplayLastFirst显示用户的姓,逗 


号,和名。 


技巧4-16 使用子过程的好处 


  维护多个子过程要比维护一个大过程要容易得多 


  由一个子过程执行的任务可以给好几个过程使用 


  每个子过程再放入主过程里之前就被单独测试 


  多个程序员可以负责各自的子过程,这些子过程再构建一个大的程序 






17.接下来…… 






在本章里,你学习了子过程和函数之间的区别:子过程执行操作;函数返回数值。而且你可以通过 


录制或者输入来创建子过程,函数则不可以录制,因为它们可能需要参数,你必须手动输入。你看 


到了从工作表或者其他VB过程调用的函数实例。 


你学习了如何给函数传递自变量,决定函数结果的数据类型。你在你的VBA关键字的系统里增加了 


ByVal,ByRef和Optional等关键字。你也看到如何将问题分割为更小更简单的任务,以使你的程序 


更容易理解。最后,你学习了子过程如何在参数的帮助下,将数值传递回到主调过程。 


过了本章后,你应该能够创建适合你特定需要的你自己的自定义函数了。你应该可以通过使用 


MsgBox和InputBox函数轻松地和用户互动。第五张将介绍程序抉择,你将学习如何基于你提供的情 


形结果改变你的VBA过程的方向。 






                           第五章 基于 VBA 做决定 






作者:Julitta Korol  翻译:Tiger Chen Jan 16’ 2005 


我们每天要作成千上万个决定,有些决定是自发的,我们自动地作出了这些决定,而不需要停下来 


去想。其它的决定则需要我们事先两个或者两个以上的选择甚至计划好几个任务。VBA和其它的编 


程语言一样,提供了专门的语句允许你在自己的程序中包含抉择点。但是,什么是做决定呢?举例 


说某人问你这个问题:“你喜欢红色吗?”想过这个问题之后,你将回答“是”或者“不”。如果你 


不确定或者根本就不关心这个问题,你也许就回答“也许”或“可能”。在编程中,你必须决断, 


只有“是”或“否”的答案是允许的。在编程中,所有的决定都是基于提供的答案作出的。如果答 


案是肯定的,程序就会执行某段特定的指令;如果答案是否定的,程序则将执行另外一段指令或者 


干脆就不做任何操作。在本章,你将学习如何使用VBA条件语句来改变你的程序流向。条件语句通 


常称为“控制结构”,因为它们使你能够控制你的VBA过程的走向,跳过某些语句以及“分叉”到程 


序的另外一部份去了。 






1.关系和逻辑运算符 






你在你的VBA过程里面通过使用专门的控制结构里的条件表达式来做决定。条件表达式是使用关系 


运算符(见表5-1),逻辑运算符(见表5-2)或者两者结合的表达式。当VB在你程序里遇到条件表 


达式时,它将评估该表达式是对还是错。 


表5-1 VBA中的关系运算符 


运算符                     描述 


=                       等于 


<>                      不等于 


>                       大于 




----------------------- Page 119-----------------------


                                                                           102 




----------------------- Page 120-----------------------


<                        小于 


>=                       大于等于 


<=                       小于等于 






表5-2 VBA中的逻辑运算符 


运算符                      描述 


AND                      在采取某行动前,所有的条件都必须为真(TRUE) 


OR                       在采取某行动前,至少有一个条件为真(TRUE) 


NOT                      用来否定条件。如果该条件为真,NOT使它为假;如果条件为假, 


                         NOT使它变真 






2.If…Then 语句 






在VBA过程里面作决定的最简单的方法就是使用If…Then语句。假使你想要基于某个条件选择一个 


行动,那么你可以使用下述结构: 


If 条件Then 语句 


例如,要删除工作表里面的空行,首先得确认当前单元格为空白的,如果测试的结果为真则继续删 


除包含本单元格在内的整行: 


If ActiveCell = "" Then Selection.EntireRow.Delete 






如果当前单元格不是空白的,VB将忽略关键字Then后面的语句。 


如果条件为真,你有时候可能想要执行好几个操作,虽然你可以在同一行加上其它的语句,通过冒 


号分隔它们,但是如果你使用多行If…Then语句,你的代码将更清晰,如下: 


If 条件Then 


  语句1 


  语句2 


  语句N 


End If 


例如,当当前单元格的数值大于50时执行一些操作,你可以编写如下指令: 


If ActiveCell.Value >50 Then 






  MsgBox "The exact value is " & ActiveCell.Value 


  Debug.Print ActiveCell.Adress & ": " & ActiveCell.Value 






End If 


在上面的例子中,如果当前单元格数值小于等于50的话,那么在关键字Then和End If之间的语句就 


不会执行。注意,If…Then语句必须以关键字End If结束。VB如何作决定呢?它评估在关键字If 


和Then中间找到的条件。我们来评估一下下面的条件:ActiveCell.Value >50 


1. 在一个空白工作表上选择任意一个单元格并输入50 


2. 切换到VB编辑器窗口 


3. 激活立即窗口 


4. 输入下述语句,并且按下回车键 


? ActiveCell.Value >50 


回车后,VB写下测试结果——false。当测试结果为假时,VB将不会读代码中关键字Then之后的语 


句,它将直接跳过去读下行代码,但是,如果没有其它的代码行时,程序就将结束。 


5. 现在,将运算符改为小于等于号,并且让VB评估下述条件: 


? ActiveCell.Value <= 50 


这次测试返回真(true),并且VB跳到关键字Then后面的语句上。 


6. 关闭立即窗口。 


既然你已经知道了VB如何评估条件的,我们就来在VBA过程里试试If…Then语句吧。 


1. 打开一个新工作簿并保存为Chap05.xls 


2. 切换到VB编辑器窗口,并且将VBA工程重命名为Decisions 


3. 插入一新模块并重命名为IfThen 






                                   103 




----------------------- Page 121-----------------------


4. 在IfThen模块里,输入下述过程: 


Sub SimpleIfThen() 


  Dim weeks As String 


  weeks = InputBox("How many weeks are in a year:", "Quiz") 






  If weeks<>52 Then MsgBox "Try Again" 


End Sub 


过程SimpleIfThen将用户的答案储存于一个名为weeks的变量上,然后,该变量的值将会和数值52 


进行比较。如果比较的结果为真(也就是说,变量weeks的值不等于52),VB就会显示信息“Try Again” 


5. 运行过程SimpleIfThen并且输入一个除52之外的数字 


6. 重新运行过程SimpleIfThen并输入数字52。当你输入正确的周数,VB将不会做任何事情,程序 


    就直接结束了。当用户猜对时,最好也显示一信息。 


7. 在关键字End Sub前的另外一行输入下述指令: 


If weeks = 52 Then MsgBox "Congratulations!" 


8. 再次运行过程SimpleIfThen并输入52。当你输入了正确的答案,VB不会执行语句MsgBox “Try 


    Again.”。如果提供的条件测试结果为假时,过程的执行结果就是忽略关键字Then右边的语句。 


    回想一下,VBA过程可以调用另外一个过程,我们来看看它是否可以调用本身 


技巧5-1 If…Then语句的两种格式 


If…Then语句有两种格式——单行和多行。这种短格式适合于可以写在一行里的语句,例如: 


If secretCode <> 01W01 Then MsgBox “Access denied” 


或者: 


If secretCode = 01W01 Then alpha=True : beta = False 






这里的secreCode,alpha和beta是变量名称。在第一个例子里,如果变量secretCode的值不等于 


01W01,那么VB显示信息“Access denied”。在第二个例子里,当变量secretCode值等于01W01时, 


VB就将变量alpha设置为真,变量beta为假。注意,执行的第二条语句用冒号与第一条语句分隔开 


来。 


如果当条件为真需要执行很多语句或将要执行的语句及其长时,多行的If…Then语句会更清楚,如 


下例所示: 


If ActiveSheet.Name = "Sheet1" Then 






ActiveSheet.Move after:=Sheets _ 


(Worksheets.Count) 


End If 


在这个例子中,VB将会检查当前工作表的名称。如果它是“Sheet1”,条件ActiveSheet .Name = 


“Sheet1”将为真,并且VB将继续执行关键字Then后面的代码行。结果,当前工作表将会被移动到 


工作簿的最后。 


9. 按下面方法修改过程SimpleIfThen里的第一个If语句: 






If weeks <> 52 Then MsgBox "Try Again" : SimpleIfThen 


我们在原来的过程SimpleIfThen后面加上一个冒号和SimpleIfThen过程名称。如果用户输入了不正 


确的答案,他将看到一信息,并且他一旦点击确定按钮后,他将获得另外一次机会来提供正确的答 


案——输入框将再次出现。用户将能够不断地猜测答案,事实上,他不能适当地推出该过程,直到 


他提供了正确的答案。如果他点击了取消按钮,他将不得不去处理不友好的错误信息“类型不匹配”。 


在上章里,你看到了如何使用On Error GoTo标志语句来绕过错误,至少你在第十三章里学习更多 


的关于错误处理的知识之前,你可以那么做。现在,你可以这样来修改你的过程SimpleIfThen: 


Sub SimpleIfThen() 


  Dim weeks As String 


  On Error GoTo VeryEnd 


  weeks = InputBox("How many weeks are in a year:", "Quiz") 


  If weeks<>52 Then MsgBox "Try Again": SimpleIfThen 






  If weeks=52 Then MsgBox "Congratulations!" 


  VeryEnd: 


End Sub 






                                     104 




----------------------- Page 122-----------------------


10. 运行几遍过程SimpleIfThen,提供一些不正确的答案。你在程序里面加的错误捕捉指令使得用 


    户可以推出猜测,而不必面对这可恶的错误信息。 






3.基于多于一个条件的决定 






在上面段落里的过程SimpleIfThen里,If…Then语句仅评估一个条件,然而,这个语句可以使用一 






个以上的条件。你必须使用逻辑运算符AND和OR(参见本章前面的表5-2)来明确If…Then语句里的 


多个条件。这里是使用AND运算符的语法: 


If 条件1 AND 条件2 Then 语句 


在上面的语法例,条件1和条件2都必须为真,VB才会执行关键字Then右边的语句。例如: 


If sales = 10000 AND salary <45000 Then SlsCom = Sales * 0.07 






在这个例子中,条件1 sales=10000,条件2 salary<45000。当AND使用在该条件表达式中时,两个 


条件都必须为真,VB才会计算销售佣金(SlsCom)。如果两个条件中只要有一个为假,或者都为假, 


VB将会忽略Then后面的语句。如果符合其中一个条件就足够好时,你就应该使用运算符OR。这里是 


语法: 


If 条件1 OR 条件2 Then 语句 


运算符OR更灵活一些,只要任何一个条件为真时,VB就会执行关键字Then后面的语句。我们来看看 


这个例子: 






If dept = "S" OR dept = "M" Then bonus = 500 


在上面的例子里,如果有个条件为真,VB就将给变量bonus赋值500。如果两个条件都为假,那么VB 


就会忽略该行剩余的代码。 


现在我们来看个完整的例子。假设如果你采购50套产品的话,就可以获得10%的折扣,单价为$7.00。 


过程IfThenAnd示范运算符AND的使用。 


1. Decisions (Chap05.xls)工程的IfThen模块里输入下述过程: 


Sub IfThenAnd() 


  Dim price As Single 


  Dim units As Integer 


  Dim rebate As Single 


  Const strmsg1 = "To get a rebate you must buy an additional " 


  Const strmsg2 = "Price must equal $7.00" 






  units = Range("B1").Value 


  price = Range("B2").Value 


  If price = 7 AND units >= 50 Then 


    rebate = (price * units) * 0.1 


    Range("A4").Value = "The rebate is: $" & rebate 






  End If 


  If price = 7 AND units < 50 Then 






    Range("A4").Value = strmsg1 & 50 - units & " unit(s)." 


  End If 


  If price <> 7 AND units >= 50 Then 


    Range("A4").Value = strmsg2 


  End If 


  If price <> 7 AND units < 50 Then 


    Range("A4").Value = "You didn't meet the criteria." 






  End If 


End Sub 


上面的过程IfThenAnd使用了四个If…Then语句来评估两个变量price和units的内容。在If…Then 


关键字之间的运算符AND使得测试多于一个的条件成为可能。使用了AND运算符时,所有条件都必须 


为真,VB才会去执行关键字Then和End之间的语句。因为过程的运行依赖于工作表单元格里输入的 


数据,所以从Excel窗口来运行它比较方便。 


2. 切换到Excel应用窗口,并且选择“工具”-“宏”-“运行宏” 






                                       105 




----------------------- Page 123-----------------------


3. 在宏对话框里,选择IfThenAnd并点击“选项”按钮 


4. 给你的宏设置快捷键:Ctrl+Shift+I,并且退出宏对话框 


5. 在工作表里输入以下数据: 






6. 按下Ctrl+Shift+I运行过程IfThenAnd 


7. 改变单元格B1和B2的值,以便你每次运行该过程时,不同的If…Then语句为真 


技巧5-2 If指令块和缩进 


要使If程序块更容易阅读和理解,可以使用缩进。对比下面的代码书写: 


If condition Then 


action1 


End If 


If condition Then 


  action 


End If 


看看下面的代码,你可以轻易知道该程序块开始在哪里,结尾又在哪里。 






4.The If…Then…Else 语句 






现在,你知道当一个或多个条件为真或为假时如何显示信息或采取行动。然而,如果你的程序需要 


在条件为真时采取某个行动,而条件为假时采取另外一个行动,应该怎么办呢?你可以通过添加一 


个Else子句就可以根据测试的结果将你的过程引导到一个合适的语句。If…Then…Else语句有两种 


格式——单行和多行。单行的格式为: 


If 条件 Then 语句1 Else 语句2 


当条件为真时,执行关键字Then后面的语句,当条件为假时,则执行Else后面的语句。例如: 


If Sales>5000 Then Bonus = Sales * 0.05 Else MsgBox “No Bonus” 


如果储存在变量Sales的值大于5000的话,那么VB将使用下述公式:Sales * 0.05来计算股红 


(bonus)。然而,如果变量Sales不大于5000的话,VB就会显示信息“No Bonus”。If…Then…Else 


语句应该用于决定执行两个操作中的哪一个。当你要执行多个语句时,你最好使用多行格式的 


If…Then…Else语句: 


If 条件 Then 


  如果条件为真时要执行的语句 


Else 


  如果条件为假时要执行的语句 


End If 


注意,多行的If…Then…Else语句以关键字End If结束。使用上面显示的缩进使得程序结构易于阅 


读。在下面的例子中,如果条件ActiveSheet.Name = “Sheet1”为真,VB就执行Then和Else之间 


的语句,并且忽略Else和End If之间的语句。当条件为假时,VB就忽略Then和Else之间的语句,并 


且执行Else和End If之间的代码。 


If ActiveSheet.Name = "Sheet1" Then 






  ActiveSheet.Name = "My Sheet" MsgBox "This sheet has been renamed." 


Else 


  MsgBox "This sheet name is not default." 






End If 


让我们来看看程序示例: 


1. 在工程Decisions(Chap05.xls)里插入一个新模块 


2. 重命名该模块为IfThenElse 


3. 输入下列过程WhatTypeOfDay: 


Sub WhatTypeOfDay() 


  Dim response As String 


  Dim question As String 


                                     106 




----------------------- Page 124-----------------------


  Dim strmsg1 As String, strmsg2 As String 






  Dim myDate As Date 






  question = "Enter any date in the format mm/dd/yyyy:" _ 


    & Chr(13)& " (e.g., 11/22/1999)" 


  strmsg1 = "weekday" 


  strmsg2 = "weekend" 


  response = InputBox(question) 


  myDate = Weekday(CDate(response)) 


  If myDate >= 2 AND myDate <= 6 Then 






    MsgBox strmsg1 


  Else 


    MsgBox strmsg2 


  End If 


End Sub 


上面的过程要求用户输入任意一个日期。用户提供的字符串通过一个内置函数CDate转变为Date数 


据类型,最好,函数Weekday将日期转变为一个指明该日期在一周里的天数(参见表5-3)。该整数 


储存于变量myDate里。条件测试用以检查变量myDate是否大于等于2以及小于等于6。如果测试结果 


为真,那么用户就被告知,该提供的数据是个工作日;否则,程序宣布这是个周末。 


表5-3 内置函数Weekday返回的值 


常数                           值 


vbSunday                     1 


vbMonday                     2 


vbTuesday                    3 


vbWednesday                  4 


vbThursday                   5 


vbFriday                     6 


vbSaturday                   7 






4. 从VB窗口运行该程序。运行几次,每次提供不同的日期。对照你的桌面或日历检查VB的答案是 


    否正确。 


技巧5-3 什么是结构化程序? 


结构化编程要求所有的程序具有模块化的设计,并使用三种逻辑结构:顺序,决定和循环。顺序结 


构为一条接一条地执行语句;决定结构则是让你基于一些条件的测试来执行一些特定的语句;而只 


要某特定的条件为真,循环结构就重复地执行某条或某些语句。循环是下章的主题。在结构化编程 


里,其它一些逻辑语句,例如GoTo,是不允许的。结构化程序的代码容易跟踪——它从上到下平稳 


地走下来,没有任何跳跃到特定标志去的语句。下面就是一个结构化程序和非结构化程序的例子: 


非结构化程序: 


  Sub GoToDemo() 


  Dim num, mystr 


    num = 1 


  If num = 1 Then 


    GoTo line1 


  Else 


    GoTo Line2 


  Line1: 


    mystr = “Number equals 1” 


    GoTo LastLine 


  Line2: 


    mystr = “Number equals 2” 


  LastLine: 






                                         107 




----------------------- Page 125-----------------------


    Debug.Print mystr 


  End sub 


结构化程序: 


  Sub Structure() 


    Dim num, mystr 


    num = 1 


    If num = 1 Then 


     mystr = “Number equals 1” 


     Debug.Print mystr 


    Else 


     mystr = “Number equals 2” 


    End if 


  End Sub 


当你在起草你的VBA程序,并且需要从一个程序的一行跳到另一行时,你可能会被使用GoTo语句所 


诱惑,不要跳跃。依赖于使用GoTo语句来你程序的路径将导致令人迷惑的代码,被称为意大利式面 


条代码。使用结构化编程,你可以轻易地到达你程序里的目的地。 


这里是另外一个示范If…Then…Else语句的过程: 


Sub EnterData() 


  Dim cell As Object 


  Dim strmsg As String 


  On Error GoTo VeryEnd 


  strmsg = "Select any cell:" 


  Set cell = Application.InputBox(prompt:=strmsg, Type:=8) cell.Select 






    If IsEmpty(ActiveCell) Then 


         ActiveCell.Formula = InputBox("Enter text or number:") 






    Else 


         ActiveCell.Offset(1, 0).Select 


    End If 


  VeryEnd: 


End Sub 


上面的字程序EnterData提示用户选择任意单元格,然后单元格地址赋值于对象变量cell 。 


If…Then…Else结构检查被选择的单元格是否为空。IsEmpty是个内置函数,用来决定某个变量是 


否已经被初始化了。如果该变量没有被初始化,那么IsEmpty函数返回true(真)。回想我们说过, 


当变量被赋予第一个值时,它就被初始化了。在本过程中,如果当前单元格为空时,VB将它当作一 


个零长度的字符串(””)。除了: 


If IsEmpty(ActiveCell) Then 


你还可以使用下述指令: 


If ActiveCell.Value = "" Then 


如果当前单元格为空,Then后面的语句就会被执行。该语句提示用户输入一个文本或数字,并且一 


旦数据被提供,该数据就会输入给当前单元格。如果当前单元格不为空,VB将跳到子句Else后面的 


指令。该指令将让VB选择同列里的下一个单元格。当你运行该过程,信息框提示你选择一个单元格, 


在工作表上,点击任何单元格。被选择的单元格地址就会出现在信息框的编辑框里面。点击确定退 


出信息框。VB检查被选择单元格的内容并且跳到你过程里的true或false指令块(true指令块在Then 


后面,而false指令块在Else后面)。 






5.If…Then…ElseIf 语句 






很多时候,你需要检查很多种情况,你可以使用子句ElseIf来将一些If条件结合在一起。使用 


If…Then…ElseIf语句,你可以比用前面章节中的If…Then…Else语句评估更多的条件。这里是 


If…Then…ElseIf语句的语法: 


If 条件1 Then 






                                      108 




----------------------- Page 126-----------------------


  条件1为真时要执行的语句 


ElseIf 条件2 Then 


  条件2为真时要执行的语句 


ElseIf 条件3 Then 


  条件3为真时要执行的语句 


ElseIf 条件N Then 


  条件N为真时要执行的语句 


Else 


  所有条件都为假时要执行的语句 


End If 


Else子句是可选的;如果当所有条件为假时,没有要执行的操作,那么你就可以忽略它。 


技巧5-4 ElseIf子句 


你的程序里可以包括任何多个ElseIf子句和条件。ElseIf子句总是出现在Else子句之前的,只有当 


ElseIf子句的条件为真时,它的语句才会被执行。 


我们来看看下述例子: 


If ActiveCell.Value = 0 Then 






  ActiveCell.Offset(0, 1).Value = "zero" 


  ElseIf ActiveCell.Value >0 Then 






       ActiveCell.Offset(0, 1).Value = "positive" 


  ElseIf ActiveCell.Value <0 Then 


       ActiveCell.Offset(0, 1).Value = "negative" 






End If 


该例检查当前单元格的值,并且在相邻的列贴上适当的“标签”(零,正和负)。注意,此时没有使 


用Else子句。如果第一种情况(ActiveCell.Value = 0)为假,VB将跳到下一个ElseIf语句,并且 


评 估 该 条 件 ( ActiveCell.Value>0 ), 如 果 该 值 不 大 于 0 , VB 将 跳 到 下 个 ElseIf 并 检 查 


条 件 


ActiveCell.Value<0。 


我们来看看If…Then…Else语句在一个完整的过程中如何工作: 


1. 在当前工程里插入一新模块 


2. 重命名模块为IfThenElseIf 


3. 输入下列过程WhatValue: 


Sub WhatValue() 


  Range("A1").Select 


  If ActiveCell.Value = 0 Then 






       ActiveCell.Offset(0, 1).Value = "zero" 


    ElseIf ActiveCell.Value > 0 Then 






       ActiveCell.Offset(0, 1).Value = "positive" 


    ElseIf ActiveCell.Value < 0 Then 






       ActiveCell.Offset(0, 1).Value = "negative" 


    ‘End If (原文错误,多一个End If) 


  End If 


End Sub 


因为你需要运行过程WhatValue好几次来测试各种条件,所以,我们给它设置个临时的快捷键。 


4. 打开立即窗口,并且输入下列语句: 


Application.OnKey "^+y", "WhatValue" 






一旦按下回车键,VB就会运行OnKey方法将过程WhatValue赋予组合键Ctrl+Shift+Y。这个键盘快捷 


键只是临时的——当你重新启动Excel后它就不起作用了。你同样也可以用Excel界面-工具菜单- 


宏对话框里的选项来设置快捷键。 


5. 切换到Excel界面,并激活Sheet1 


6. 在单元格A1里输入0,并且按下Ctrl+Shift+Y。VB将调用过程WhatValue并在单元格B1厘米输入 


    “zero” 






                                      109 




----------------------- Page 127-----------------------


7. 在单元格A1里输入任意大于0的数字,并按下Ctrl+Shift+Y,VB将再次调用WhatValue。VB评估 


    第一种条件,因为该测试的结果为假,所以它跳到ElseIf语句。第二个条件为真,因此VB执行 


    Then后面的语句,并且跳过下一条语句,直接到End If。因为End If后面并没有其它的语句了, 


    该过程便结束了,单元格B1现在显示“positive”。 


8. 在单元格A1里输入任意小于0的数字,并按下Ctrl+Shift+Y。这次,前面两个条件都返回假, 


    因此VB继续检查第三个条件。因为这次的测试为真,VB就在单元格B1里贴上标签“negative” 


9. 在单元格A1里输入任何文本,并按下Ctrl+Shift+Y,VB的反应是“positive”,然而,这不是 


    个满意的答案。你也许希望VB通过显示“text”来区分开正数和文本。要使你的过程WhatValue 


    更“聪明”些,你就需要学习如何通过使用嵌套的If…Then语句来作一些更复杂的决定。 






6.嵌套的 If…Then 语句 






将一个If…Then语句或If…Then…Else语句放在另外一个If…Then语句或If…Then…Else语句里 


面,你可以在你的VBA过程里作出更复杂的决定。这种一个If语句里包含另一个If指令块的结构称 


为嵌套的If语句。 


接下来的过程TestConditions世上节里的过程WhatValue的修正版,演示嵌套的If…Then语句是如 


何工作的: 


Sub TestConditions() 


  Range("A1").Select 


  If IsEmpty(ActiveCell) Then 


    MsgBox "The cell is empty." 


  Else 


      If IsNumeric(ActiveCell.Value) Then 






        If ActiveCell.Value = 0 Then 


            ActiveCell.Offset(0, 1).Value = "zero" 






        ElseIf ActiveCell.Value > 0 Then 


            ActiveCell.Offset(0, 1).Value = "positive" 






        ElseIf ActiveCell.Value < 0 Then 


            ActiveCell.Offset(0, 1).Value = "negative" 


        End If 


      Else 


        ActiveCell.Offset(0, 1).Value = "text" 






      End If 


  End If 


End Sub 


为了使过程TestConditions更容易理解,每个If…Then语句都显示为不同的格式,现在你可以清楚 


地看到过程使用了三个If…Then程序块。 


第一个If块(粗体)检查当前单元格是否为空,如果为真,就会显示信息,然后VB将跳过Else部分 


找到相应的End If,该语句位于关键字End Sub之前。 


如果当前单元格不为空,IsEmpty (ActiveCell)条件返回假,并且VB运行粗体Else下面的单下划线 


的If块。该单下划线的If…Then…Else语句就是嵌套在第一个If块(粗体)的。该语句检查当前单 


元格是否是个数字。注意,我们通过另一个内置函数IsNumeric来做这个。如果当前单元格的值不 


是一个数字,条件就为假,因此,VB跳到单下划线的Else处,并且在B1里输入“text”。然而,如 


果当前单元格包含个数字时,VB就会运行双下划线的If块,评估每种情况并作出相应的决定。 


第一个If块(粗体)被称为外部If语句,这个外部语句包含两个内部的If语句(单下划线和双下划 


线)。 


技巧5-5 嵌套语句 


嵌套是指将一种控制结构放在另外一控制结构里面。你将在第六章里的循环结构里看到更多的嵌套 


的例子。 






7.Select Case 语句 






为了避免难以弄清的复杂的嵌套的If语句,你可以使用Select Case语句代替。它的语法为: 






                                    110 




----------------------- Page 128-----------------------


Select Case 测试表达式 


Case 表达式1 


  如果表达式1匹配测试表达式的语句 


Case 表达式2 


  如果表达式2匹配测试表达式的语句 


Case 表达式N 


  如果表达式N匹配测试表达式的语句 


Case Else 


  如果没有表达式匹配测试表达式要执行的语句 


End Select 


你在关键字Select Case和End Select之间放置任意多个条件以测试。子句Case Else是可选的,当 


你希望可能有条件表达式返回假时使用它。在Select Case语句里,VB将每个表达式和测试表达式 


相比较。 


这里是Select Case语句背后的逻辑。当VB遇到Select Case子句,它记下测试表达式的值。然后它 


前进到下面的第一个Case子句,如果这个表达式的值和测试表达式的值匹配的话,VB就会执行语句 


直到遇到另外一个Case子句并且跳到End Select语句。然而,如果第一个Case子句后面的表达式测 


试结果和测试表达式不匹配时,VB就会检查每一个Case子句,直到它找到一个匹配的为止。如果没 


有一个Case子句后面的表达式匹配测试表达式的值的话,VB就会跳到Case Else子句并执行该语句 


直到遇到关键字End Select。注意,Case Else子句是可选的,如果你的程序里面没有使用Case Else 


并且没有一个Case子句的表达式和测试表达式相匹配,VB就会跳到End Select后面的语句,并且继 


续执行你的程序。 


我们来一个使用Select Case语句的程序例子。在第四章里,你学习了MsgBox函数允许你显示带有 


一个或多个按钮的信息,你也学习了MsgBox函数的结果可以赋予一个变量。使用Select Case语句, 


你现在可以基于用户按下的按钮决定采取哪个行动。 


1. 在当前工程里插入一新模块 


2. 重命名新模块SelectCase. 


3. 输入下述过程TestButtons: 


Sub TestButtons() 


  Dim question As String 


  Dim bts As Integer 


  Dim myTitle As String 


  Dim myButton As Integer 


  question = "Do you want to open a new workbook?" 






  bts = vbYesNoCancel + vbQuestion + vbDefaultButton1 


  myTitle = "New Workbook" 






  myButton = MsgBox(prompt:=question, buttons:=bts, _ title:=myTitle) 


  Select Case myButton 


    Case 6 


        Workbooks.Add 


    Case 7 






        MsgBox "You can open a new book manually later." 


    Case Else 


        MsgBox "You pressed Cancel." 


  End Select 


End Sub 


过程TestButtons的第一部分显示一个带有三个按钮的信息框:是,否和取消。用户选择按钮的值 


赋予变量myButton。 


如果用户点击“是”,那么变量myButton就会被赋值常量vbYes或它对应的值6;如果用户点击“否”, 


那么变量myButton则赋值为常量vbNo或它对应的值7;最后,如果点击了“取消”,变量myButton 


的内容就等于vbCancel或2。 






                                     111 




----------------------- Page 129-----------------------


Select Case语句对照储存在变量myButton里的值检查Case子句提供的值。当有匹配时,就会执行 


适当的Case语句。 


如果你使用常量,而不是按钮值,过程TestButtons同样会运行一致。 


Select Case myButton 


  Case vbYes 


       Workbooks.Add 


  Case vbNo 






       MsgBox "You can open a new book manually later." 


  Case Else 


       MsgBox "You pressed Cancel." 


End Select 


你可以忽略Else子句,可以按下述方法修改一下Select Case语句: 


Select Case myButton 


  Case vbYes 


       Workbooks.Add 


  Case vbNo 






       MsgBox "You can open a new book manually later." 


  Case vbCancel 


       MsgBox "You pressed Cancel." 


End Select 


4. 运行过程TestButtons三次,每次选择一个不同的按钮。 


技巧5-6 通过Case Else捕捉错误 


尽管在Select Case语句里使用Case Else不是强制的,使用它总是很好的,以防止万一测试有没有 


预料到的值。Case Else子句是个放置错误信息的好地方。 






8.和 Case 子句一起使用 Is 






有时候,作决定是基于测试表达式的条件,例如它是否大于,小于,等于或使用一些其它的关系运 


算符(参见表5-1)。关键字Is使你能够在Case子句里使用条件表达式。使用关键字Is的Select Case 


语句的语法如下: 


Select Case 测试表达式 


Case Is 条件1 


  如果条件1为真时执行的语句 


Case Is 条件2 


  如果条件2为真时执行的语句 


Case Is 条件N 


  如果条件N为真时执行的语句 


End Select 


例如,我们来比较几个数字: 


Select Case myNumber 


  Case Is <10 


       MsgBox "The number is less than 10" 






  Case 11 


       MsgBox "You entered eleven." 


  Case Is >=100 


       MsgBox "The number is greater than or equal to 100." 






  Case Else 


       MsgBox "The number is between 12 and 99." 


End Select 


假设变量myNumber为120,那么第三个Case子句为真,并且只有Case Is >=100和Case Else之间的 


语句会被执行。 






                                        112 




----------------------- Page 130-----------------------


9.确定 Case 子句里数值的范围 






在前面的例子里,你看到了在每个Case子句里使用一个简单表达式。然而,很多时候,你可能需要 


在Case子句里确定一个数值范围。可以通过关键字To用于表达式的数值之间来实现它,如下所示: 


Select Case unitsSold 


  Case 1 to 100 


       Discount = 0.05 


  Case Is <= 500 


       Discount = 0.1 


  Case 501 to 1000 


       Discount = 0.15 


  Case Is >1000 


       Discount = 0.2 


End Select 


我们来分析一下上面的Select Case代码块,假设变量unitsSold当前值为99。VB将变量unitsSold 


的值与Case子句的条件表达式进行比较。第一和第三条Case子句示范如何通过使用关键字To在条件 


表达式里使用数值范围。因为unitsSold=99,第一个Case子句里的条件表达式为真,因此,VB将0.05 


赋给变量Discount。第二个Case子句如何呢?它也为真。尽管,很明显99小于等于500,VB不会执 


行相关的语句Discount=0.1。原因是,一旦VB找到了一个真条件的Case子句,它就不会去管其它的 


Case子句,它将跳过那些代码,继续执行End Select语句后面可能有的语句。 


我们来练练使用Select Case语句,在函数过程里使用它。回想在第四章里,函数过程允许你将结 


果返回给一个子过程。假设该子过程必须根据销售的套数来显示一个折扣,你可以从用户那里获得 


销售套数,然后允许一个函数来确定需要的折扣: 


1. 在模块SelectCase里输入下列子过程: 


Sub DisplayDiscount() 


  Dim unitsSold As Integer 


  Dim myDiscount As Single 


  unitsSold = InputBox("Enter the number of sold units:") 


  myDiscount = GetDiscount(unitsSold) 






  MsgBox myDiscount 


End Sub 


2. 输入下列函数过程: 


Function GetDiscount(unitsSold As Integer) 


  Select Case unitsSold 


     Case 1 To 200 


       GetDiscount = 0.05 


     Case Is <=500 


       GetDiscount = 0.1 


     Case 501 To 1000 


       GetDiscount = 0.15 


     Case Is >1000 


       GetDiscount = 0.2 


  End Select 


End Function 


3. 将光标放在过程DisplayDiscount的任意地方并且按下F5来运行它。 


过程DisplayDiscount将储存于变量unitsSold的值传递给函数GetDiscount。当VB遇到Select Case 


语句时,它检查第一个Case子句里的值是否合储存于unitsSold里面的值是否匹配。如果匹配,VB 


给函数名称赋值百分之五(0.05),并且跳到关键字End Select。因为,在函数过程里面没有更多需 


要运行的语句,VB就返回主调过程——DisplayDiscount,在这里,它将函数的结果赋予变量 


myDiscount。最后的语句用信息框来显示获得的折扣。 






                                        113 




----------------------- Page 131-----------------------


10.在 Case 子句里确定多个表达式 






你可以使用逗号明确单一Case子句里的多个表达式: 


Select Case myMonth 


  Case "January", "February", "March" 






      Debug.Print myMonth & ": 1st Qtr." 


  Case "April", "May", "June" 


      Debug.Print myMonth & ": 2nd Qtr." 


  Case "July", "August", "September" 


      Debug.Print myMonth & ": 3rd Qtr." 






  Case "October", "November", "December" 


      Debug.Print myMonth & ": 4th Qtr." 


End Select 


技巧5-7 Case子句的多个条件 


用来分隔开Case子句里面多个条件的逗号,和用于If语句里的运算符OR意义一样。只要这些条件有 


一个为真,Case子句就为真。 






11.接下来… 






在本章介绍的条件语句,让你控制你的过程走向。通过测试条件的真假,你可以决定哪些语句需要 


执行,哪些要跳过。换句话说,不必从上到下,一行一行地运行你的过程,你可以只执行某些行, 


如果你犹豫应该使用哪种条件语句,这里是一些指南: 


  如果你只要提供一个条件,简单的If…Then语句是最好的选择 


  如果你要决定运行两个条件中的一个,那么使用If…Then…Else语句 


  如果你的程序需要两个或多个条件,那么使用If…Then…ElseIf或者Select Case语句 


  如果你的程序有很多条件,那么就使用Select Case语句。这个语句比If…Then…ElseIf语句 


   更灵活并且更容易理解。 


有些决定是需要重复的,例如,你可能需要在工作表里的每个单元格里或者一个工作簿里的每个表 


里重复同样的操作。下章将教你如何一次又一次地做同样的操作。 






                           第六章 在 VBA 中重复操作 






作者:Julitta Korol  翻译:Tiger Chen Feb 1’ 2005 


既然你已经学习了条件语句如何赋予你的VBA过程作决定的能力,是时候深入了。不是所有的决定 


都容易,有时候你将需要运行一些语句好几次才能达到某个条件。然而,另一方面,当你达到这个 


决定后,你可能需要一直运行某些语句,只要条件为真,或直到条件变为真。在编程中,重复地执 


行任务被称为循环。VBA有好些个循环结构,允许你多次重复一系列的语句。你将在本章里学习如 


何循环你的代码。 






1.Do Loops: Do…While 和 Do…Until 






VB有两种Do循环语句,只要或者直到某个条件为真,它们就会重复一系列的语句。只要条件为真, 






Do…While循环就允许你重复某个操作。这个循环的语法如下: 


Do While 条件 


  语句1 


  语句2 


  语句N 


Loop 


当VB遇到这个循环时,它首先条件的真假,如果条件为假,循环内部的语句就不会被执行,VB将继 


续执行关键字Loop后面的第一条语句。如果条件为真,循环里面的语句则会被一条一条地执行,直 


到遇到Loop语句。Loop语句告诉VB重复这个过程,只要Do While语句里的条件为真的话。 


现在,我们来看看如何在Excel里面好好利用Do…While循环语句。在第四章里,你学习了如何根据 


一个单元格的内容来作决定。让我们再进一步,看看如何在一系列单元格上作同样的决定。该决定 


是给一列中的非空单元格设置粗体格式。 






                                   114 




----------------------- Page 132-----------------------


1. 打开一个空工作簿,并且命名为Chap06.xls 


2. 切换到VB编辑屏幕,并且将新工程改名为Repetition (Chap06.xls) 


3. 在工程Repetition里插入一新模块,并重命名为DoLoops 


4. 输入如下过程: 


Sub ApplyBold() 


  Do While ActiveCell.Value <>"" 


    ActiveCell.Font.Bold = True 


    ActiveCell.Offset(1, 0).Select 


  Loop 


End Sub 


5. 在单元格A1:A7里输入任意数据(文本或数字) 


6. 选择单元格A1 


7. 选择“工具”-“宏”-“运行宏”。在宏对话框里,双击过程ApplyBold(或者选中该过程然后 


   点击运行) 


当运行过程ApplyBold时,VB首先评估Do While语句里的条件——ActiveCell.Value<>””,该条 


件意思是:只要当前单元格的值不是一个空字符串(””),就执行下列语句。因为你已经在单元 


格A1里输入了数据并且激活了该单元格(见第六步),第一个测试返回真,所以VB执行语句 


ActiveCell.Font.Bold = True,它的意思是给当前单元格设置粗体格式。接下来,VB选择了下一 


行的单元格(参见第二章里的Offset属性)。因为该语句之后就是关键字Loop,VB返回到Do While 


语句,并且再次检查条件。如果新选中的单元格(当前激活的单元格)不为空,那么VB就会重复循 


环内部的语句。该过程会继续,直到检查到单元格A8的内容为空,测试条件的结果为假,因此,VB 


就跳过循环内部的语句。并且在关键字Loop后面没有其它的语句了,所以该过程就结束了。 


我们来看看另外一个Do…While循环的例子。是不是很想知道如何在Excel的状态栏里显示今天的日 


期和时间?这里有个例子,如何让它显示十秒钟: 


Sub TenSeconds() 


  Dim stopme 


  stopme = Now + TimeValue("00:00:10") 


  Do While Now < stopme 






    Application.DisplayStatusBar = True 


    Application.StatusBar = Now 


  Loop 


  Application.StatusBar = False 


End Sub 


在上面的程序里,只要函数Now返回的时间小于变量stopme的值,Do…While循环里的语句就会被执 


行。变量stopme储存值为当前时间加上十秒(参见在线帮助里的另外一个使用内置函数TimeValue 


的例子)。 


语句Application.DisplayStatusBar告诉VB打开状态栏的显示,下条语句则是将当前日期和时间放 


在状态栏上。当显示时间时(只显示10秒)用户无法使用系统(光标变成了沙漏)。十秒钟后(也 


就是,当条件Now < stopme为真),VB跳出循环并且执行关键字Loop后面的语句,该语句将状态栏 


返回到默认信息“就绪”。 


技巧6-1 什么是循环? 


循环是一种导致一部分程序代码重复执行的编程结构。VBA提供了多种结构在你的过程里执行循环: 


Do…While, Do…Until, For…Next, For…Each, and While…Wend 


Do…While循环还有另外一种语法,你可以在循环的底部测试条件,例如: 


Do 


  语句1 


  语句2 


  语句N 


Loop While 条件 


当你在循环的底部测试条件时,意味着循环里面的语句至少运行了一次。看一下这个例子: 






                                   115 




----------------------- Page 133-----------------------


Sub SignIn() 


  Dim secretCode As String 






  Do secretCode = InputBox("Enter your secret code:") 


      If secretCode = "sp1045" Then Exit Do 






  Loop While secretCode <> "sp1045" 


End Sub 


注意,在条件被测试之时,VB至少已经执行了一次循环里的语句。除了将条件放在循环之后外,过 


程SignIn示范如何使用条件跳出循环。当Exit Do语句执行时,循环便立即停止。 


技巧6-2 避免无限循环 


如果你没有正确地设计你的循环,你将导致一无限循环——永无休止的循环。你将无法使用Esc键 


来停止该循环。在下面的过程里,因为用户忘了放置测试条件而导致了永无休止的循环: 


Sub SayHello() 


 Do 


      MsgBox "Hello." 


 Loop 


End Sub 


你必须按下Ctrl+Break键(译者:现在,有些电脑使用别的组合键来中断程序。例如我的手提电脑 


就是Fn+Break)才能终止该无限循环,当VB显示信息“代码执行被中断”时,点击结束以退出过程。 


另外一种方便的循环Do…Until,也可以让你重复一条或多条语句,直到条件为真。换句话说, 


Do…Until语句是只要当某个条件为假的时候重复一块代码。这是它的语法: 


Do Until 条件 


    语句1 


    语句2 


    语句N 


Loop 


使用上面的语法,你可以将前面的过程ApplyBold重新写成下面的方式: 


Sub ApplyBold2() 


  Do Until IsEmpty(ActiveCell) 


    ActiveCell.Font.Bold = True 


    ActiveCell.Offset(1, 0).Select 


  Loop 


End Sub 


该过程的第一条语句意思是执行下列语句,直到遇到第一个空单元格。结果上,如果当前单元格不 


为空,VB就执行循环内部的那两条语句。只要条件IsEmpty(ActiveCell)测试为假,这个过程就反 


复继续着。因为过程ApplyBold2在循环的前面就测试条件,如果第一个单元格就为空的话,循环内 


部的语句就不会运行。在下一段,你将有机会试验它。 


和Do…While循环类似,Do…Until循环也有第二种语法让你在循环的底部测试条件: 


Do 


    语句1 


    语句2 


    语句N 


Loop Until 条件 


如果你想要程序至少执行一次,那么就将条件放置于Loop语句一行,无论条件的值是什么。 


我们来试验一下下面的例子,该例子将工作簿里的空工作表删除。 


1. 在你前面创建的DoLoop模块里输入下面的过程DeleteBlankSheets: 


Sub DeleteBlankSheets() 


  Dim myRange As Range 


  Dim shcount As Integer 


  shcount = Worksheets.Count 


  Do 






                                     116 




----------------------- Page 134-----------------------


    Worksheets(shcount).Select 






    Set myRange = ActiveSheet.UsedRange 






    If myRange.Address = "$A$1" And _ 


      Range("A1").Value = "" Then 


        Application.DisplayAlerts = False 


        Worksheets(shcount).Delete 


        Application.DisplayAlerts = True 


    End If 


    shcount = shcount - 1 


  Loop Until shcount = 1 


End Sub 


2. 手动在当前工作簿里面插入一些工作表。在一个工作表里输入一些数据与单元格A1;另一个工 


   作表的单元格B2和C10里输入一些数据;第三个工作表里不要输入任何数据。 


3. 运行过程DeleteBlankSheets。当你运行该过程时,无论何时,只要两个条件都为真——属性 


   UsedRange返回单元格A1并且A1为空,VB就会删除所选的工作表。属性UsedRange应用于对象 


   Worksheet,包含工作表中的每个非空单元格以及他们之间的空单元格。例如,如果你在单元 


   格B2和C10里输入里东西(译者:包括格式),使用了的区域为$B$2:$C$10。如果你后面又在A1 


   里输入了数据,那么UsedRange将会是$A$1:$C$10。已使用区域是一个从左上角最远的地方到 


   右下角最远的地方包围起来的区域。因为工作簿至少要保留一个工作表,所以代码执行到变量 


   shcount等于1时就停止了。语句shcount = shcount-1确保变量shcount在循环里面的代码每执 


   行一次就减少1。变量shcount的值在过程的开始处用下列语句:Worksheets.Count初始化了。 


   注意,当删除工作表的时候,Excel通常会显示一个确认对话框,如果你不想看到这个确认提 


   示框的话,就是要下列语句: 


   Application.DisplayAlerts = False 


   当你完成任务时,使用下列语句,再打开系统信息。 


   Application.DisplayAlerts = True 


技巧6-3 计数器 


计数器是个数字变量,用来追踪已进行的项目次数。上面的过程DeleteBlankSheets声明了变量 


shcount来追踪检查的工作表个数。计数器变量必须在程序的开始就被初始化(赋值),这可以确保 


你总能在开始使用之前知道计数器的确切值。计数器可以按照确定的值增加或减少。参见本章后面 


的使用计数器的For…Next循环。 






2.观察过程执行 






当你使用循环结构运行过程时,有时很难看到该过程会按预期地执行。有时,你很想观察程序慢慢 


地运行,这样你就能够检查该程序的逻辑。我们来看看VB如何让你一行接一行地执行程序。 


1. 在单元格区域A1:A5里面输入任何数据 


2. 选择单元格A1 


3. 在Excel窗口,选择“工具”-“宏”-“运行宏” 


4. 在宏对话框里,选择ApplyBold2并点击“单步执行”按钮。VB编辑屏幕将出现,过程的名称被 


   黄色加亮(参加图6-1)。注意代码窗口左边的黄色箭头。 






                                   117 




----------------------- Page 135-----------------------


图6-1 观察程序一行接一行地执行 


5. 使VB窗口缩小一些,可以点击VB标题栏的“还原”按钮缩小窗口 


6. 按下F8,黄色加亮区将跳到DoUntil IsEmpty(ActiveCell)行 


7. 继续按F8,同时观察代码和工作表窗口 






3.While…Wend 循环 






While…Wend循环功能上和Do…While循环一样,它是从Microsoft Basic的早期版本遗留下来的并 


且VBA保留它也是为了支持兼容性。该循环以关键字While开始以关键字Wend结束。这是它的语法: 


While 条件 


  语句1 


  语句2 


  语句N 


Wend 


条件在循环的上面就被测试,只要提供的条件为真,这些语句就会被执行。一旦条件为假,VB就将 


退出该循环。我们来看一个使用While…Wend循环结构的过程: 


1. 在当前工程里插入一新模块,重命名为WhileLoop 


2. 输入下述过程: 


Sub ChangeRHeight() 


  While ActiveCell <>"" 


    ActiveCell.RowHeight = 28 


    ActiveCell.Offset(1, 0).Select 


  Wend 


End Sub 


3. 在单元格区域B1:B4里输入一些数据 


4. 选 择 单 元 格 B1 并 且 运 行 过 程 ChangeRHeight 。 当 当 前 单 元 格 不 为 空 时 , 上 


面 的 过 程 


   ChangeRHeight将设置行高位28。 






                                   118 




----------------------- Page 136-----------------------


4.For…Next 循环 






当你知道你需要重复运行多少次某段语句时,可以使用For…Next语句。它的语法如下: 


For 计数器 = 开始 To 结束 [步长] 


  语句1 


  语句2 


  语句N 


Next [计数器] 


括号里面的代码是可选的。计数器是个储存反复次数的数字型变量,开始是你期望的起始计数点, 


结束则表明循环应该执行多少次。 


例如,你想要重复执行循环里的语句5次,使用下述For语句: 


For counter = 1 To 5 


      你的语句 


Next 


当VB遇到关键字Next时,它将回到循环的开始处,并且再次执行循环里面的代码,直到计数器到达 


结束值。一旦计数器的值大于关键字To后面的数值,VB就会跳出循环。因为计数器变量在每次执行 


循环后会自动地变化,它早晚会超出结束的值。每次VB执行循环里的语句后,变量计数器的值会默 


认地增加1,你可以使用Step语句来改变这个默认设置。例如,要使计数器每次增加3,就可以使用 


以下语句: 


For counter = 1 To 5 Step 3 


      你的代码 


Next counter 


当VB遇到上面的语句,它会执行循环里的语句两次。在第一次的循环里,counter等于1,第二次则 


等于4(3+1)。在执行两次循环后,counter就等于7(4+3),这导致VB退出该循环。 


注意,步长(Step)是可选的。可选语句总是显示则方括号里面(参加本段开头部分的语法)。步 


长不需要明确,除非它不等于1。你可以在Step后面放个负值作为步长,那么VB每次遇到关键字Next 


后都会将计数器减小。 


关键字Next后面的变量名称(counter)也是可选的,然而,好的编程习惯是要强制在关键字Next 


后面加上计数器。 


如何将For…Next循环使用在Excel里面呢?假使你只想要在你的销售报告里面包括某几个特定月 


份的产品销售,当你从Access导入数据时,你同样也会将那些销售额为0的数据行一起导入。你如 


何快速取出数据为0的行呢?尽管,有很多种方法可以解决这个问题,但是,我们来看看如何使用 


For…Next循环来处理这个问题吧。 


1. 在VB窗口,在当前工程里插入一个模块并且命名为ForNextLoop 


2. 在ForNextLoop模块里输入下列过程: 


Sub DeleteZeroRows() 


  Dim totalR As Integer 


  Dim r As Integer 


  Range("A1").CurrentRegion.Select 


  totalR = Selection.Rows.Count 


  Range("B2").Select 


  For r = 1 To totalR-1 


    If ActiveCell = 0 Then 


      Selection.EntireRow.Delete 


      totalR = totalR – 1 


    Else 


      ActiveCell.Offset(1, 0).Select 


    End If 


  Next r 


End Sub 


3. 切换到Excel界面,并且准备下述表格: 






                                   119 




----------------------- Page 137-----------------------


             A                     B 


1 Product Name            Sales (in Pounds) 


2 Apples                  120 


3 Pears                   0 


4 Bananas                 100 


5 Cherries                0 


6 Blueberries             0 


7 Strawberries            160 






4. 运行过程DeleteZeroRows。 


我们来一行接一行地检查一下过程DeleteZeroRows。开始两语句计算当前区域的总行数,并且将该 


值储存于变量totalR,接下来,VB选择单元格B2然后遇到关键字For。因为电子表格的第一行包含 


了列标题,所以要从总行数里减掉1(totalR-1)。VB将需要执行循环里面的指令6次。 


嵌套在循环里面的条件语句(If…Then…Else)告诉VB根据当前活动单元格的值作出决定。如果该 


值为0,VB就删除当前行,并且将总行数减掉1。否则,条件为假,因此,VB将选择下一行的单元格。 


VB每完成一次循环,它就跳到关键字For来比较r的值和totalR-1的值。当过程结束后,销售表里就 


不会包含没有销售的产品了。 


技巧6-4 成对语句 


For和Next必须是成对的,如果有一个漏掉了,VB就将产生一个错误信息“For没有Next” 






5.For Each…Next 循环 






当你的过程需要在一个集合的所有对象或者一个数组的所有元素(数组将在第七章里涉及)之间循 


环时,应该使用For Each…Next循环。该循环不需要计数器变量,VB自己知道应该执行几次循环。 


我们拿工作表集合作个例子,要删除工作簿里面的工作表,你首先不得不要选择它,再选择“编辑” 


-“删除工作表”。如果要只留一个工作表在工作簿里面的话,你就不得不使用同样的命令,次数取 


决于工作表的总数。因为每个工作表都是工作表集合里的一个对象,所以使用For Each…Next循环 


来加速删除工作表。该循环的形式是: 


For Each 元素 In 组合 


  语句1 


  语句2 


  语句N 


Next [元素] 


在上面的语法中,元素一个数组或者集合的所有元素都将被赋予的变量,如果是数组的话,该变量 


必须为Variant数据类型;如果是集合的话,则必须是个对象数据类型。组合是集合的名称或者数 


组的名称。 


现在,我们来使用For Each…Next循环删除工作表。 


1. 在当前工程里插入新模块并且重命名为ForEachNextLoop 


2. 在模块ForEachNextLoop里输入下列过程: 


Sub RemoveSheets() 


  Dim mySheet As Worksheet 


  Application.DisplayAlerts = False 


  Workbooks.Add 


  Worksheets("Sheet2").Select 


  For Each mySheet In Worksheets 


    ActiveWindow.SelectedSheets.Delete 


  Next mySheet 


End Sub 


3. 运行过程RemoveSheets。 


VB将会打开一个新工作簿并且删除除Sheet1之外的所有工作表。注意,变量mySheet代表工作表集 


合里的所有对象。除了按通常的方法将对象变量声明为Object类型,你还可以将它声明为更具体的 






                                   120 




----------------------- Page 138-----------------------


对象类型,这样会更好。在这个具体的例子里,你可以使用下面的声明: 


Dim mySheet As Worksheet 


而不是: 


Dim mySheet As Object 


第一条指令Application.DisplayAlerts = False让Excel在过程运行的时候不要显示警告和信息。 


如果你忽略了它,Excel将会要你确认是否删除所选的工作表。接下来,过程打开一个新工作簿并 


且选择Sheet2。For Each…Next循环遍历每个工作表(从所选的Sheet2开始)并且删除它们。当过 


程结束的时候,该工作簿只剩一个工作表Sheet1了。 


这里是另外一个检查某个工作表是否存在于一工作簿中: 


Sub IsSuchSheet() 


  Dim mySheet As Worksheet 


  Dim counter As Integer 


  counter = 0 


  For Each mySheet In Worksheets 


    If mySheet.name = "Sheet2" Then 


      counter =counter + 1 


    End If 


  Next mySheet 


  If counter = 1 Then 


      MsgBox "This workbook contains Sheet2." 


  Else 


      MsgBox "Sheet2 was not found." 


  End if 


End Sub 






7.提前跳出循环 






有时候,你并不想等到循环自己结束,可能是用户输入了错误的数据,过程遇到了错误或者可能是 


任务已经完成并且没有必要作更多的循环。你可以提前跳出循环,而不必等到条件正常结束。VB 


有两种Exit语句: 


  Exit For语句用来提前退出For…Next或者For Each…Next循环 


  Exit Do语句立即退出任何VBA Do 循环 


下面的过程示范如何使用Exit For语句提前跳出For Each…Next循环: 


1. 在当前模块里输入下列过程: 


Sub EarlyExit() 


  Dim myCell As Range 


  For Each myCell in Range("A1:H10") 


    If myCell.Value = "" Then 


      myCell.Value = "empty" 


    Else 


      Exit For 


    End If 


  Next myCell 


End Sub 


EarlyExit过程检查特定区域A1:H10里每个单元格的内容,如果当前单元格为空,VB就会在当前单 


元格力输入文本“empty”。当VB遇到第一个非空单元格,它就会跳出循环。 


2. 打开一个新工作簿并且在单元格区域A1:H10的任意单元格里输入数据 


3. 运行过程EarlyExit 


技巧6-5 退出过程 


如果你想提前退出子过程,那么可以使用Exit Sub语句。如果该过程是一个函数的话,就使用Exit 


Function语句代替就行。 






                                       121 




----------------------- Page 139-----------------------


8.循环嵌套 






到目前为止,你已经在本章里尝试了很多种循环了,每种过程示范每个循环结构的使用。然而,在 


编程中,一循环总是放在另外一循环中的。VB允许你将不同类型的循环(For和Do循环)“嵌套”在 


同一个过程里。当你编写循环嵌套时,请确保每个内部的循环在外部循环里面已经完成。另外,每 


个循环都必须有其自己独特的计数器变量。如果使用循环嵌套,你可以更有效地执行特定的任务。 


下面显示的过程ColorLoop示范如何嵌套一个For…Next循环在另一个For…Next循环里面: 


Sub ColorLoop() 


  Dim myRow As Integer 


  Dim myCol As Integer 


  Dim myColor As Integer 


  myColor = 0 


  For myRow = 1 To 8 


    For myCol = 1 To 7 


      Cells(myRow, myCol).Select 


      myColor = myColor + 1 


      With Selection.Interior 


        .ColorIndex = myColor 


        .Pattern = xlSolid 


      End With 


    Next myCol 


  Next myRow 


End Sub 


上面的过程ColorLoop使用了两个For…Next循环来改变工作表中前面八行和七列里的每个单元格 


的颜色。当外部的循环在追踪行号的时候,内部的循环在做更多的事情,它首先确定当前的列号, 


基于当前的行号的列号选择适当的单元格,然后给所选的单元格设置颜色。 


内部的For…Next循环给工作表的第一行的七个单元格(A1, B1, C1, D1, E1, F1和G1)设置不同 


的颜色。当变量myCol大于7时,VB跳回外部循环并且变量myRow增加1,再回到内部循环去设置下一 


行单元格的颜色。当过程结束时,56个单元格(8*7)被设置了当前调色板上可用的所有颜色。第 


一个单元格,A1,被设置了黑色(颜色索引号为1),第二个单元格B1则被设置为白色了(颜色索引 


号为2)。每次单元格地址变化——Cells(myRow, myCol).Select——变量myColor的内容也会改变 


——myColor = myColor + 1 






9.接下来… 






在本章里,你学习了如何在循环里重复一组代码。通过使用好几种类型的循环,你看到了每种循环 


稍稍不同地进行重复。你有了经验后,你将更容易地选择合适的控制结构来执行你的任务。 


在本书的后续章节中,将会有更多的使用循环的例子。例如,在下章里,你将看到如何使用数组合 


嵌套的循环来创建一个VBA过程,该过程将帮你选择彩票号码。在下章里,你将学习如何处理大量 


的数据,而不会迷失在变量的海洋里。 






                     第七章 利用 VBA 数组管理数据清单和表格 






作者:Julitta Korol  翻译:Tiger Chen Feb 1’ 2005 


在前面的章节里,你在很多VBA过程里使用变量来储存特定的对象信息,属性或者数值。对于你想 


要处理的单个数值,你可以声明变量,但是,对于一系列的数值呢?如果你不得不编写VBA过程来 


处理大量的数据,你就得声明足够的变量来处理所有的数据。你能想象将世界上所有国家的货币交 


换利率储存在你的程序的噩梦吗?要创建一个表格来储存这些必要的数据的话,你至少要给每个国 


家创建三个变量:国家名称,货币名称和交换比率。幸运的是,VB有方法来解决该问题。将相关的 


变量归为一类,你的VBA过程可以轻松处理大量的数据。在本章里,你将学习如何使用数组来操作 


数据清单和数据表。 






                                   122 




----------------------- Page 140-----------------------


1.了解数组 






在VB里,数组一种特殊的变量,代表拥有相同数据类型(字符串,整型,货币,日期,等等)的一 






组相似的数值。两种最通常的数组是一维数组(清单)和二维数组(表格)。有时,一维数组被称 


为清单。一维数组或编号清单的例子有:购物清单,星期名称的清单或员工清单。清单里面的每个 


值都有一个索引。下面是一个含有六个成员的清单的图解: 


项目(1) 


项目(2) 


项目(3) 


项目(4) 


项目(5) 


项目(6) 


注意,列代表一维的当前为空的数组。如果你想用数据填充这个数组,只要使用一个变量名称,附 


带括符编号就行,而不需要使用六个不同的标签。在上面的图解里,“项目”一变量名称,括号里 


的数字明确数组里的每个成员。 


数组的所有成员都必须具有相同的数据类型,换句话说,一个数组不能同时储存字符串和整型数据。 


接下来的图解是一维数组的两个例子:第一个叫做cities的一维数组由文本组成(字符串数据类型 


——$),第二个叫做lotto的一维数组则包含六个抽奖号码(整数数据类型——%)。 






   一维数组cities$ (字符串数据类型)                  一维数组lotto% (整数数据类型) 


         Cities(1) Baltimore                     Lotto(1) 25 


         Cities(2) Atlanta                       Lotto(2) 4 


         Cities(3) Boston                        Lotto(3) 31 


         Cities(4) Washington                    Lotto(4) 22 


         Cities(5) New York                      Lotto(5) 11 


         Cities(6) Trenton                       Lotto(6) 5 






正如你看到的,每个数组成员的内容和变量的数据类型是相匹配的。如果你想要在同一个数组里面 


储存不同数据类型的数据,那么你必须将数据声明为Variant。 


二维数组是由行和列代表的数据表。表中每个成员的位置是由它的行和列号码决定的。下面是一个 


空的二维数组的图解。 






    行号 1          2        3        列号 


       1 (1,1)    (1,2)    (1,3) 


       2 (2,1)    (2,2)    (2,3) 


       3 (3,1)    (3,2)    (3,3) 


       4 (4,1)    (4,2)    (4,3) 


       5 (5,1)    (5,2)    (5,3) 






注意,二维数组里的项目是如何有行和列索引指定的?在该图解里,数组里的第一个成员位于第一 


行和第一列里(1,1),而最后一个成员则位于第五行和第三列里的(5,3)。下面,我们来给该数组填 


充一些数据。下面显示的二维数组储存了国家名称,它的货币名称以及和美元的汇率。 


Japan      Japanese Yen    128.2 


(1,1)      (1,2)           (1,3) 


Mexico     Mexican Peso    9.423 


(2,1)      (2,2)           (2,3) 


Canada     Canadian Dollar 1.567 


(3,1)      (3,2)           (3,3) 


Norway     Norwegian Krone 8.351 


(4,1)      (4,2)           (4,3) 






                                   123 




----------------------- Page 141-----------------------


Hungary     Hungarian Forint 266.7 


(5,1)       (5,2)          (5,3) 


尽管VBA数组最大可以拥有60维,但是,绝大多数人发现非常困难去想象超过三维的数组。三维的 


数组是一个具有相同行数和列数的表格的集合。在三维数组里的每个成员由下面三个数据决定:行 


号,列号和表格号。 


技巧7-1 数组变量是什么? 


数组是拥有共同名称的变量的集合。一个典型的变量只能储存一个数据,然而,一个数组变量却能 


够储存大量的变量。你可以使用变量名称和索引号来指向数组中某个确定的数据。 


技巧7-2 下标变量 


数组变量的括号里的数字成为下标,而每个单独的变量则称为下标变量或成员。例如,cities(6) 


是cities数组里的第六个下标变量(成员)。 






2.声明数组 






因为数组也是变量,所以,你必须用声明其它变量的类似方法声明数组——使用Dim语句。当你声 


明一个数组时,你便设定了该数组储存数据所需要的内存空间。 


我们来看看一个数组声明的例子: 


Dim cities(6) As String 


Dim daysOfWeek(7) As String 


Dim lotto(6) As Integer 


Dim exchange(5, 3) As Variant 


注意,变量名称后面带有括号以及括号里有数字。一维数组要求括号里带一个数字,这个数字决定 


了这个数组能够储存的最大成员数。二维数组后面总是带有两个数字——第一个数字是行索引号, 


而第二个数字是列索引号。在上面的例子里,数组exchange最多可以储存15个数据(5*3=15)。 


数组声明的最后一部份是定义数组将要储存数据的数据类型。数组可以储存下列任何一种数据类 


型:Integer, Long, Single, Double, Variant, Currency, String, Boolean, Byte, or Date。 


当你声明了一个数组,VB会自动占据足够的内存空间,分配的内存空间取决于该数组的大小和数据 


类型。当你声明一个名叫lotto的带有6个成员的一维数组时,VB将留出12个字节——数组的每个成 


员各占2个字节(回想整型数据类型为2个字节,因此2*6=12)。数组越大,储存数据需要的内存空 


间就越大。因为数组会吃掉很多内存,并因此影响你电脑的运行,因此,建议你仅仅根据你可能使 


用的成员数来声明数组。 






3.数组的上界和下界 






VBA默认将数组的第一个成员设置为0(译者:索引号),因此,数字1代表数组中的第二个成员,而 


数字2则代表第三个,等等。因为数字编号起始于0,所以,一维数组cities(6)包含从0到6的七个 


成员。如果你宁愿从1开始计数你数组里的成员,那么你可以使用Option Base 1语句来强制指定该 


数组的下界。该指令必须置于VBA模块任何Sub语句上面的声明部分。如果你不明确Option Base 1, 


那么VBA在使用数组是就会假定使用Option Base 0来从0开始编号你的数组成员。 


你也可以让数组从除0或1之外的数字开始编号,要达到该目的,你在声明数组变量时就必须明确该 


数组的边界。数组的边界是指它最小和最大的索引号。我们来看看下面的例子: 


Dim cities(3 To 6) As Integer 


上面的语句声明了一个带有四个成员的一维数组。数组名称后面括号里的数字明确了数组的下界 


(3)和上界(6)。该数组的第一个成员编号为3,第二个为4,第三个为5,以及第四个为6。注意 


下界和上界之间的关键字To。 


技巧7-3 数组范围 


Dim语句明确的数组的下标区间就称为数组的范围,例如:Dim mktgCodes(5 To 15) 






4.在 VBA 过程里使用数组 






你声明了数组后,就必须给该数组的每个成员赋值,这也经常成为“填充数组”。我们来尝试使用 


一维数组有规划地显示六个美国城市的清单: 


1. 打开一个新工作簿,并保存为Chap07.xls 


2. 切换到VB编辑器窗口,并重新命名VBA工程为Tables 


                                   124 




----------------------- Page 142-----------------------


3. 插入一新模块,重新命名为StaticArrays 


4. 输入下列过程FavoriteCities: 


' start indexing array elements at 1 从1开始给数组成员编号 


Option Base 1 


Sub FavoriteCities() 


'now declare the array 


Dim cities(6) As String 






'assign the values to array elements 


cities(1) = "Baltimore" 


cities(2) = "Atlanta" 


cities(3) = "Boston" 


cities(4) = "Washington" 


cities(5) = "New York" 


cities(6) = "Trenton" 


'display the list of cities 


MsgBox cities(1) & Chr(13) & cities(2) & Chr(13) _ 






  & cities(3) & Chr(13) & cities(4) & Chr(13) _ 


  & cities (5) & Chr(13) & cities(6) 


End Sub 


在FavoriteCities过程开始之前,缺省的索引编号方式改变了,注意,Option Base 1语句是位于 


模块窗口Sub语句之上的。该语句告诉VB给数组的第一个成员赋值数字1,而不是缺省的0。 


数组cities()声明为带六个成员的字符串类型变量。然后,给数组的每个成员都赋上了值。最后的 


语句使用Msgbox函数显示城市清单。当你运行该过程时,城市名称将会出现在分开的行上(参见图 


7-1)。你可以改变显示数据的顺序,改变索引号。 






图7-1 你可以用Msgbox函数来显示一维数组的成员 


5. 运行FavoriteCities过程并且检查结果 


6. 修改FavoriteCities过程,让它逆序显示城市名称(从6到1) 


技巧7-4 数组成员的初始值 


在给数组成员赋值之前,该成员具有缺省值。数字变量的缺省值为0,而字符串变量的缺省值为空 


字符串。 






5.数组和循环语句 






现在要执行一些例如填充数组或显示数组成员的任务了,你在第六章里学过的好些个循环语句(参 


见For…Next和For Each …Next循环)就变得非常方便了。现在是时候将你所学到的技巧结合起来 


使用了。如何重新编写FavoriteCities过程,让每个城市名称在不同的信息框里显示出来? 


下面显示的过程FavoriteCities2将原来过程的最后部分取代为For Each…Next循环: 


Sub FavoriteCities2() 


  'now declare the array 


  Dim cities(6) As String 


  Dim city As Variant 


  'assign the values to array elements 






                                       125 




----------------------- Page 143-----------------------


  cities(1) = "Baltimore" 


  cities(2) = "Atlanta" 


  cities(3) = "Boston" 


  cities(4) = "Washington" 


  cities(5) = "New York" 


  cities(6) = "Trenton" 


  'display the list of cities in separate messages 






  For Each city in cities 


       MsgBox city 


  Next 


End Sub 


注意For Each…Next循环使用的是Variant数据类型的变量city。回想在前面的章节里,For 


Each…Next让你在一个集合的所有对象间或者一个数组的所有的成员间循环,并且对每个对象或成 


员执行同样的操作。当你运行过程FavoriteCities2时,数组里有几个成员循环就会执行几次。 


我们来看一下过程FavoriteCities的另一种变化。在第四章里,你练习了将参数作为变量传递给子 


过程和函数。过程FavoriteCities3示范了如何将数组的成员传递给另一个过程。 


1. 在当前模块里,输入下述两个过程: 


Sub FavoriteCities3() 


  'now declare the array 


  Dim cities(6) As String 


  'assign the values to array elements 






  cities(1) = "Baltimore" 


  cities(2) = "Atlanta" 


  cities(3) = "Boston" 


  cities(4) = "Washington" 


  cities(5) = "New York" 


  cities(6) = "Trenton" 


  'call another procedure and pass the array as argument 






  Hallo cities() 


End Sub 


Sub Hallo (cities() As String) 


  Dim counter As Integer 


  For counter = 1 to 6 


       MsgBox "Hello " & cities(counter) 


  Next 


End Sub 


过程Hallo的声明里有一个数组类型的参数——cities()。 


2. 运行过程FavoriteCities3。将一个子过程的数组成员传递给另一个子过程或者函数过程让你 


    可以在许多过程里使用相同的数组,而不需要重复的程序代码。 


技巧7-5 在过程之间传递数组 


当一个数组在一个过程里被声明时,它是局部的,并且是不为其他过程所知的。然而,你可以将局 


部数组传递给其它的过程,通过在声明语句里,写上数组名称,并且后面紧跟一对空括号。例如, 


语句Hallo cities() 调用一个名叫Hallo的过程,并且将数组cities()传递给它。 


这里有个例子,如何将你新学到的关于数组的知识和循环运用到现实生活中。如果你是个狂热的彩 


票玩家的话,当你厌倦了选择你的幸运号码,你可以让VB为你选择。下面的过程Lotto使用1到51 


的六个数字填充数组: 


Sub Lotto() 


  Const spins = 6 


  Const minNum = 1 


  Const maxNum = 51 






                                         126 




----------------------- Page 144-----------------------


   Dim t As Integer ‘looping variable in outer loop 外部循环变量 


   Dim i As Integer ‘looping variable in inner loop 内部循环变量 


   Dim myNumbers As String ‘string to hold all picks 储存选号的字符串 


   Dim lucky(spins) As String ‘array to hold generated picks 储存产生的选号的数组 


   myNumbers = "" 


   For t = 1 To spins 


     Randomize 






     lucky(t) = Int((maxNum-minNum+1) * Rnd )+ minNum) 


     'see if this number was picked before 检查本数字是否之前被选出来过 


     For i = 1 To (t-1) 


        If lucky(t)=lucky(i) Then 


               lucky(t) = Int((maxNum–minNum+1) * Rnd)+ minNum) i = 0 


        End If 


     Next i 






     MsgBox "Lucky number is " & t & lucky(t) 


     myNumbers = myNumbers & " –" & lucky(t) 


   Next t 


   MsgBox "Lucky numbers are " & myNumbers 






End Sub 


Randomize语句将随机数字发生器初始化。指令Int((maxNum-minNum+1) * Rnd + minNum)使用函数 


Rnd来产生一个在minNum和maxNum之间的随机数值。函数Int将随机数转变为一个整数。除了给 


minNum和maxNum赋予常量之外,你也可以使用函数InputBox从用户那里获得数据。 


内部For…Next循环确保每个选出的数字是唯一的——它不能是之前选出的任何一个数字。如果你 


忽略了内部循环并且多次运行该过程,你很可能看到重复的号码。 






6.使用二维数组 






既然你已经知道了如何有规划地产生一个清单(一维数组),是时候仔细看一下如何使用数据表了。 


下面的过程产生一个二维数组,储存国家名称,货币名称和交换汇率。 


Sub Exchange() 


  Dim t As String 


  Dim r As String 


  Dim Ex(3, 3) As Variant 


     t = Chr(9) 'tab 


     r = Chr(13) 'Enter 


     Ex(1, 1) = "Japan" 


     Ex(1, 2) = "Yen" 


     Ex(1, 3) = 128.2 


     Ex(2, 1) = "Mexico" 


     Ex(2, 2) = "Peso" 


     Ex(2, 3) = 9.423 


     Ex(3, 1) = "Canada" 


     Ex(3, 2) = "Dollar" 


     Ex(3, 3) = 1.567 






     MsgBox "Country " & t & t & "Currency" & t & "per US$" _ 


       & r & r _ 






       & Ex(1, 1) & t & t & Ex(1, 2) & t & Ex(1, 3) & r _ 


       & Ex(2, 1) & t & t & Ex(2, 2) & t & Ex(2, 3) & r _ 


       & Ex(3, 1) & t & t & Ex(3, 2) & t & Ex(3, 3), , _ 






       "Exchange" 


End Sub 






                                            127 




----------------------- Page 145-----------------------


当你运行过程Exchange时,你将看到一个信息框,显示三列信息(见图7-2) 






图7-2 显示在信息框上的文本是可以自定义格式的。 






7.静态和动态数组 






到目前为止,本章介绍的都是静态数组。静态数组是具有确定大小的数组。当你事先知道数组的大 


小时使用静态数组。静态数组的大小是在数组的声明语句里确定的,例如,语句Dim Fruits(10) As 


String声明了一个由10个成员组成的叫做Fruits的静态数组。 


但是,万一你不肯定你的数组会包含多少个成员呢?如果你的过程由用户输入决定,每次程序执行 


时,用户提供的成员数可能会变化的。你如果确保你声明的数组不会浪费内存呢? 


回想你声明了一个数组后,VBA会留出足够的内存来储存数组。如果你声明一个比你需要的更多成 


员的数组的话,你将浪费计算机资源。这个问题的解决方法是让你的数组变为动态的。动态数组是 


大小可以改变的数组。如果数组的大小每次都由程序运行而决定的话,就使用动态数组。 


技巧7-6 固定大小的数组 


静态数组包含固定成员个数。静态数组的成员个数在它被声明后就再也不能改变了。 


要声明动态数组,那么不要在数组名称后面的括号里放置数字: 


Dim Fruits( ) As String 


动态数组通过在数组名称后面附带空括号来声明。在你使用动态数组于过程里之前,你必须使用 


ReDim语句来动态地设置数组的上界和下界。ReDim语句随着程序代码的执行重新设定数组大小, 


ReDim语句通知VB数组的新大小,这个语句可以在同一个过程里多次使用。现在,我们来看看如何 


使用动态数组。 


1. 在当前工程里插入一个新模块并且重新命名为DynamicArrays 


2. 输入下列过程DynArray: 


Sub DynArray( ) 


  Dim counter As Integer 


  'declare a dynamic array 


  Dim myArray( ) As Integer 


  'specify the initial size of the array 






  Redim myArray(5) 


  Workbooks.Add 


  'populate myArray with values 


  For counter = 1 to 5 


    myArray(counter) = counter +1 


    ActiveCell.Offset(counter-1, 0).Value = myArray(counter) 


  Next 






  'change the size of myArray to hold 10 elements 


  Redim Preserve myArray(10) 


  'add new values to myArray 


  For counter = 6 To 10 






    myArray(counter) = counter * counter 


    With ActiveCell.Offset(counter-1, 0) 


      .Value = myArray(counter) 


      .Font.Bold = True 






                                      128 




----------------------- Page 146-----------------------


    End with 


  Next counter 


End Sub 


3. 将你的Excel窗口和VB编辑器窗口并排显示 


4. 逐步运行过程DynArray。你可以将鼠标置于代码中间,并且按下F8来执行逐条语句。程序 


    DynArray的结果如下图所示。 






图7-3 显示10个数据的数组 


在过程DynArray里,Dim myArray() As Integer语句声明了一个叫做myArray的动态数组。尽管该 


语句声明了数组,但是,没有分配任何内存给该数组。第一条ReDim语句明确了myArray的开始大小 


并且占据了10个字节的内存让它储存5个成员,正如你所知,每个整型数据需要两个字节的内存。 


语句Workbooks.Add打开一新工作簿,然后For…Next循环用数据填充数组myArray并且将数组的成 


员写入工作表。在循环开始之前,变量counter等于1。循环里的第一条语句: 


myArray(counter) = counter + 1 


分配数值2给myArray的第一个成员。第二条语句: 


ActiveCell.Offset(counter-1, 0).Value = myArray(counter) 






将myArray成员的值输入到当前单元格里。当前单元格为A1。因为变量counter等于1,所以上面的 


语句就等于: 






ActiveCell.Offset(1-1, 0).Value = myArray(1) 


或者 


ActiveCell.Offset(0,0).Value = myArray(1) 






上面的语句在单元格A1里输入数据。循环里面的语句被执行5次。VB在合适的工作表单元格里马输 


入数据并且进行到下一语句: 


ReDim Preserve myArray(10) 


通常,当你改变一个数组的大小时,你将失去该数组原来的所有数据。语句ReDim将数组重新初始 


化。 


然而,你可以将新成员加入到现存的数组里去,通过在语句ReDim后面带上关键字Preserve。换句 


话说,关键字Preserve保证重新改变大小的数组不会弄丢现有的数据。如果你忽略它,新数组将会 


是空的。 


第二个For…Next循环给数组myArray的第六,第七,第八,第九和第十个成员赋值。这次,数组成 


员的数值是相乘的:counter * counter。VB使用粗体将数组其它的数值输入到合适的工作表的单 


元格里面。 


技巧7-7 确定数组大小 


在使用数组之前,必须在Dim或ReDim语句里确定数组的大小。这意味着你不可以给数组成员赋值, 


直到你使用Dim或者ReDim语句声明了该数组。 






8.数组函数 






你可以通过五个VBA内置函数来操作数组:Array, IsArray, Erase, LBound和UBound。接下来的章 






                                    129 




----------------------- Page 147-----------------------


节将示范每个函数在VBA过程里的使用。 






9.Array 函数 






Array函数允许你在代码执行中间创建一个数组,而不必事先确定其大小。该函数总是返回一个 


Varant数组。使用函数Array你可以快速地将一系列数据放置在一个清单里面。下面的过程CarInfo 


创建了一个叫做auto的固定大小,一维的三个成员的数组。 


1. 在当前工程里插入一新模块,重命名为Array_Function 


2. 输入下列过程CarInfo: 


Option Base 1 


Sub CarInfo() 


     Dim auto As Variant 


     auto = Array("Ford", "Black", "1999") 






  MsgBox auto(2) & " " & auto(1) & ", " & auto(3) 


     auto(2) = "4-door" 


  MsgBox auto(2) & " " & auto(1) & ", " & auto(3) 






End Sub 


另外一个例子,示范如何使用Array函数将列标输入到工作表里: 


Sub ColumnHeads() 


  Dim heading As Variant 


  Dim cell As Range 


  Dim i As Integer 


  i = 1 






  heading = Array("First Name", "Last Name", "Position", _ 


  "Salary") 


  Workbooks.Add 


  For Each cell in Range("A1:D1") 


     cell.Formula = heading(i) 


     i = i+1 


  Next 


  Columns("A:D").Select 


  Selection.Columns.AutoFit 


  Range("A1").Select 


End Sub 






10.IsArray 函数 






使用IsArray函数你可以测试某个变量是否数组。如果该变量是个数组,那么IsArray函数返回True, 


否则返回False。请看例子: 


1. 在当前工程里插入模块,命名为IsArray_Function 


2. 输入如下过程IsThisArray: 


Sub IsThisArray() 


  'declare a dynamic array 声明一动态数组 


  Dim sheetNames() As String 


  Dim totalSheets As Integer 


  Dim counter As Integer 


  'count the sheets in the current workbook 计数当前工作簿里的工作表数目 


  totalSheets = ActiveWorkbook.Sheets.Count 






  'specify the size of the array 明确数组大小 


  ReDim sheetNames(1 To totalSheets) 


  'enter and show the names of sheets 输入和显示工作表名称 


  For counter = 1 to totalSheets 


     sheetNames(counter) = ActiveWorkbook.Sheets(counter).Name 






                                           130 




----------------------- Page 148-----------------------


     MsgBox sheetNames(counter) 


  Next counter 


  'check if this is indeed an array 检查它是否确实为数组 


  If IsArray(sheetNames) Then 






     MsgBox "The sheetNames is an array." 


  End If 


End Sub 






11.Erase 函数 






当你要清除数组里的数据时,应该使用Erase函数。该函数删除静态或动态数组储存的所有数据, 






另外,对于动态数组,Erase函数将重新分配原来分配给该数组的所有内存。下面的例子教你如何 


删除数组cities里的数据。 


1. 在当前工程里插入一新模块,重命名为Erase_Function 


2. 输入如下过程FunCities: 


' start indexing array elements at 1 






Option Base 1 


Sub FunCities() 


  'declare the array 


  Dim cities(1 to 5) As String 






  'assign the values to array elements 


  cities(1) = "Las Vegas" 


  cities(2) = "Orlando" 


  cities(3) = "Atlantic City" 


  cities(4) = "New York" 


  cities(5) = "San Francisco" 


  'display the list of cities 






  MsgBox cities(1) & Chr(13) & cities(2) & Chr(13) _ 


     & cities(3) & Chr(13) & cities(4) & Chr(13) _ 


     & cities (5) 


  Erase cities 


  'show all that was erased 






  MsgBox cities(1) & Chr(13) & cities(2) & Chr(13) _ 


     & cities(3) & Chr(13) & cities(4) & Chr(13) _ 


     & cities (5) 


End Sub 


在函数Erase清除数组里的数据后,函数MsgBox就显示一个空信息框了。 






12.LBound 函数和 UBound 函数 






LBound函数和UBound函数分别返回表明数组的下界和上界的数字。 


1. 在当前工程里插入模块,命名为L_and_UBound_Function 


2. 输入如下代码FunCities2: 


Sub FunCities2() 


  'declare the array 


  Dim cities(1 to 5) As String 






  'assign the values to array elements 


  cities(1) = "Las Vegas" 


  cities(2) = "Orlando" 


  cities(3) = "Atlantic City" 


  cities(4) = "New York" 


  cities(5) = "San Francisco" 


  'display the list of cities 


                                             131 




----------------------- Page 149-----------------------


  MsgBox cities(1) & Chr(13) & cities(2) & Chr(13) _ 






    & cities(3) & Chr(13) & cities(4) & Chr(13) _ 






    & cities (5) 


  'display the array bounds 






  MsgBox "The lower bound: " & LBound(cities) & Chr(13) _ 


    & "The upper bound: " & UBound(cities) 


End Sub 


当你要确定一个二维数组的上下界时,你就必须明确维数:1表示第一维,2表示第二维。 


在本章早先时候将的Exchange过程里的后面加上如下语句,可以确定该二维数组的上下界(将下列 


代码加入到关键字End Sub之前): 


MsgBox "The lower bound (first dimension) is " _ 






       & LBound(Ex, 1) & "." 


MsgBox " The upper bound(first dimension) is " _ 


       & UBound(Ex, 1) & "." 






MsgBox "The lower bound (second dimension) is " _ 


       & LBound(Ex, 2) & "." 






MsgBox " The upper bound(second dimension) is " _ 


       & UBound(Ex, 2) & "." 






13.数组中的错误 






使用数组时,出错是很容易的。如果你试图给数组赋予比声明数组时更多的成员的话,VBA就会显 


示错误信息“下标越界” 






图7-4 该错误出现于试图访问并不存在的数组成员 


假设你声明了一个包含6个成员的一维数组,而你却试图给第八个成员赋值,当你运行该过程时, 


VB无法找到第八个成员,所以显示错误信息。点击调试按钮,VB将导致错误的代码行(见图7-5) 


加亮。检查数组的声明语句,并且更改被加亮代码行括号里的索引号。 


“下标越界”错误经常是由使用循环的过程引发的。下面的过程Zoo1就是这种情况的一个例子。在 


用户取消在输入框里输入数据之前,循环里的语句反复被执行。在执行该过程时,当变量 i 等于4 


的时候,VB无法在这个只有三个成员的数组里找到第四个成员,那么错误信息就出现了。修改后的 


过程Zoo2示范了前面章节里介绍的LBound和UBound函数如何能够避免试图访问不存在的数组成员 


的错误。 






                                       132 




----------------------- Page 150-----------------------


图7-5 当你点击错误信息的调试按钮,VB就会加亮引发错误的语句 


1. 在当前工程里插入新模块,命名为Errors_In_Arrays 


2. 输入下列过程Zoo1和Zoo2: 


Sub Zoo1() 


   'this procedure triggers an error "Subscript out of range" 本过程引发“下标越界”错 


   误 


   Dim zoo(3) As String 


   Dim i As Integer 


   Dim response As String 


   i = 0 


   Do 


     i = i +1 






     response = InputBox("Enter a name of animal:") 


     zoo(i) = response 


   Loop until response = "" 


End Sub 


Sub Zoo2() 


   'this procedure avoids the error "Subscript out of range"本过程避免“下标越界”错误 


   Dim zoo(3) As String 


   Dim i As Integer 


   Dim response As String 


   i = 1 


   Do While i>=LBound(zoo) And i <=UBound(zoo) 


     response = InputBox("Enter a name of animal:") 






     If response = "" Then Exit Sub 


     zoo(i) = response 


     i = i + 1 


   Loop 


   For i = LBound(zoo) To UBound(zoo) 


        MsgBox zoo(i) 


   Next 


End Sub 






                                             133 




----------------------- Page 151-----------------------


另外一个使用数组时经常碰到的错误是类型不匹配。要避免这类错误,就要牢记一个数组的每个成 


员都必须具有相同的数据类型。如果你试图给数组成员赋予和数组声明的数据类型矛盾的数据的 


话,你就将在执行代码时收到“类型不匹配”的错误。要让一个数组出错不同类型的数据类型的话, 


你就得声明数组为Variant类型。 






14.数组作为参数 






在第四章里面,你学习了数据可以在子过程或者函数过程之间作为必须或者可选参数传递。如果传 


递的参数不是过程执行一定要的话,那么这个参数名称就应该在前面加关键字Optional。然而,有 


些时候,你事先并不知道你要传递多少个参数。一个典型的例子就是加法。你可能想要将两个数字 


加和,或者,你也许要加和3个,10个,或者15个数字。使用关键字ParamArray,你就可以将一个 


包含任意个成员的数组传递给你的子过程和函数过程。下面的函数过程AddMultipleArgs将加和你 


所需要的任何多个数字。该函数以数组myNumbers的声明开始,注意关键字ParamArray的使用。该 


数组必须声明为Variant类型,并且它必须是函数过程的最后一个参数。 


1. 在当前工程里插入一新模块,命名为ParameterArrays 


2. 输入如下函数过程AddMultipleArgs: 






Function AddMultipleArgs(ParamArray myNumbers() As Variant) 


  Dim mySum As Single 


  Dim myValue As Variant 


  For each myValue in myNumbers 


      mySum=mySum+myValue 


  Next 


  AddMultipleArgs = mySum 


End Function 


3. 激活立即窗口来试验上面的函数,在立即窗口里输入指令: 






?AddMultipleArgs(1, 23.24, 3, 24, 8, 34) 


当你按下回车键,VB就会返回上面参数的总和:93.24。你可以提供无限制的参数数目。注意,每 


个函数的参数之间要用逗号分开。 






15.接下来… 






在本章里,你学习了通过创建数组,你可以编写需要大量变量的过程。通过例子,示范了如何声明 


和使用一维数组(清单)和二维数组(表)。你也学习了静态数组和动态数组之间的差别。本章的 


结尾介绍了五个VBA内置函数和关键字ParamArray,它们经常使用于数组。 


现在你已经知道了可以使你的程序更智能的控制结构了:条件语句,循环和数组。在本书的后面, 


你将学习如何使用集合代替数组来操作更大量的数据。通过使用从第一到第七章学到的知识,你现 


在可以开始编写VBA过程让你的任务自动化了,而这些在你开始学习本书之前似乎是不可能的事情。 


接下来的一章将讲述文件和文件夹的管理。 






                       第八章 利用 VBA 操纵文件和文件夹 






作者:Julitta Korol  翻译:Tiger Chen Mar 5’ 2005 


在工作过程中,你肯定访问、创建、复制和删除过成百上千的文件和文件夹。然而,你可能从未用 


程序执行过这些任务。所以,现在就是机会。本章侧重于专门处理文件和文件夹的VBA函数和指令。 


通过使用这些函数,你将能够: 


•  获得当前文件夹的名称(CurDir函数) 


•  更改文件和文件夹名称(Name函数) 


•  检查某文件或文件夹是否存在于某硬盘上(Dir函数) 


•  获取某文件最后修改的时间和时间(FileDateTime函数) 


•  获取文件大小(FileLen函数) 


•  检查和更改文件属性(GetAttr和SetAttr函数) 


•  更改缺省文件夹或者硬盘(ChDir和ChDrive语句) 


•  创建和删除文件夹(MkDir和RmDir语句) 


•  复制和删除文件或文件夹(FileCopy和Kill语句) 


                                   134 




----------------------- Page 152-----------------------


此外,本章也给你往三类文件写入或者读取数据的知识:连续的,随机的和二进制的文件。除了使 


用Excel应用软件界面之外,你将学习如何直接操作文件。在本章的最后,将给你介绍最新的操作 


文件和文件夹的方法,通过利用称为Windows Scripting Host (WSH)的工具来操作文件和文件夹。 


操作文件和文件夹 


本节将讨论多种操作文件和文件夹的函数。 






1.获取当前文件夹的名称(CurDir 函数) 






当你使用文件时,经常会需要知道当前文件夹的名称,你使用CurDir函数轻易地获取该信息: 


CurDir([drive]) 


Drive是一可选参数,如果你忽略它,VBA将使用当前驱动(drive)。 


CurDir函数返回一个文件路径作为Variant(变量)。如果要返回作为字符串(String)的路径的话, 


就得使用CurDir$(这里的$是字符串的类型声明字符)。让我们在立即窗口里做些练习,练习使用 


这些函数吧: 


1. 打开一个新工作簿,并且切换到VB编辑器窗口 


2. 激活立即窗口并敲入下述代码: 


?CurDir 


当你按下回车,VB就显示当前文件夹名称,例如: 


C:\ 


如果你有第二个硬盘(或者光驱)的话,你可以获取D盘上的当前文件夹,例如: 


?CurDir(“D:\”) 


如果你提供了一个并不存在的驱动字母的话,VB就将显示下述错误信息:“设备不可用” 


3. 要储存当前驱动名称到变量myDrive,可以输入下述指令: 


myDrive = Left(CurDir$,1) 


当你按下回车键时,VB将当前驱动器的字母储存到变量myDrive 


敲入下述指令并回车,可以检查变量myDrive的内容: 


?myDrive 


你还可以将上面的指令改为如下: 


myDrive = left(CurDir$,1) & ":" 


VB将返回驱动器字母,后面带有一个冒号。 






2.更改文件或文件夹名称(Name 函数) 






使用函数Name可以重命名文件或者文件夹,例如: 


Name old_pathname As new_pathname 


Old_pathname是你想用重命名的文件或文件夹的名称和路径,New_pathname则明确文件或文件夹的 


新名称和位置。使用函数Name,你可以将一个文件从一个文件夹移动到另外一个文件夹,但是,你 


不可以移动文件夹。 


请在立即窗口里试演该函数(用你文件的实际名称替换示例名称)。这里有些需要考虑的注意事项: 


•  在New_pathname里的文件名称不要指向已经存在的文件 


Name "C:\System.1st " As "C:\test.txt" 






因为文件C:\test.txt已经存在于C盘,VB将显示错误信息:“文件已存在”,同样,如果你要重命名 


的文件不存在的话,就会出现“文件未找到”的错误信息。 


•  如果New_pathname已经存在,并且和Old_pathname不同,函数Name必要时将文件移动到新文件 


   夹并且更改它的名称。 


Name "C:\System.1st " As "D:\test.txt" 






                                                 st 


因为文件test.txt在D盘的根目录下并不存在,VB将C:\System.1移动到指定的驱动盘,然而,并 


不重命名该文件。(译者:本段与上面的内容似乎矛盾,而且未能试验成功,未知是原书失误与否。 


读者应仔细验证) 


•  如果New_pathname和Old_pathname指向不同的目录,以及提供的文件名称相同,那么Name函数 


   将指定的文件移到新地址,不用更改文件名。 


Name "D:\test.txt " As "C:\DOS\test.txt" 


上面的指令将test.txt移动到C盘下的DOS文件夹里。 


                                  135 




----------------------- Page 153-----------------------


技巧8-1 你不能重命名开启的文件 


在重命名文件之前,你必须关闭该文件。文件名称里不能包含通配符“*”或者“?”。 






3.检查文件或文件夹是否存在(Dir 函数) 






Dir函数,返回文件或者文件夹名称,语法如下: 


Dir[(pathname[, attributes])] 


Dir函数的两个参数都是可选的,pathname是文件或文件夹名称,对于参数attributes,你可以下 


列常量或者数值之一: 


表8-1 文件属性 


   常量                     数值           属性名称 


   vbNormal               0            Normal 普通文件 


   vbHidden               2            Hidden 隐藏文件 


   vbSystem               4            System 系统文件 


   vbVolume               8            Volume label 卷标 


   vbDirectory            16           Directory or Folder 目录或文件夹 






Dir函数常用来检查某个文件或文件夹是否存在,如果不存在,那么就返回空字符串(””)。我们 


到立即窗口里试验几个Dir函数的练习: 


1. 在立即窗口,输入下述指令: 


?Dir("C:\", vbNormal) 


你一旦按下回车键,VB就会返回该文件夹下的第一个文件名。普通文件(vbNormal)就是除隐藏, 


卷标,目录,文件夹或系统文件之外的任何文件。 


要返回当前目录下的其它文件名称的话,就使用不带参数的Dir函数: 


?Dir (并且回车) 


2. 在立即窗口里输入下列指令,并且在你回车时检查其结果: 


mfile = Dir("C:\", vbHidden) 


?mfile 


mfile = Dir 


?mfile 


mfile = Dir 


?mfile 


3. 在立即窗口输入下述指令: 


If Dir("C:\stamp.bat") = "" Then Debug.Print "文件未找到。" 


因为stamp.bat文件不在C盘上,所以VB就在立即窗口里写下文本信息“文件未找到。” 


4. 在立即窗口输入下述语句,可以检查某文件是否存在于某驱动盘上: 


If Dir ("C:\Autoexec.bat") <>"" Then Debug.Print "该文件不在C盘上。" 


函数Dir允许你在文件路径名中使用通配符——星号(*)代表多个字符,问号(?)代表单个字符: 


例如,要在WINDOWS文件夹中查找所有配置设置的文件,你可以查找所有的INI文件,如下: 


?Dir("C:\WINNT\*.ini", vbNormal) 


system.ini 


?dir WIN.INI 


?dir 


WINFILE.INI 


?dir control.ini 


?dir EQUIP32.INI 


?dir 


sxpwin32.ini 


下面显示的过程在立即窗口里写上了确定目录下的文件名称。函数LCase$让文件名称显示为小写字 


母。 


1. 打开一新工作簿,并保存为Chap08.xls 






                                    136 




----------------------- Page 154-----------------------


2. 切换到VB编辑器窗口并重命名VBA工程为FileMan 


3. 插入新模块,重命名为DirFunction 


4. 输入下述VBA过程: 


Sub MyFiles() 


Dim mfile As String 


Dim mpath As String 


mpath = InputBox("Enter pathname,e.g., C:\Excel") 






If Right(mpath, 1) <> "\" Then mpath = mpath & "\" 


mfile = Dir(mpath & "*.*") 






If mfile <> "" Then Debug.Print "Files in the " & mpath _ 


       & "folder" 


       Debug.Print LCase$(mfile) 


       If mfile = "" Then 


              MsgBox "No files found." 


              Exit Sub 


       End If 


       Do While mfile <> "" 


              mfile = Dir 


              Debug.Print LCase$(mfile) 


       Loop 


End Sub 


上面的过程myFiles向用户询问文件路径名。如果该路径结尾没有反斜杠,函数Right就会将反斜杠 


附加在路径名字符串上。接下来,VB在该确定的文件夹里搜索所有文件(*)。如果没有文件的话, 


就会有信息显示,如果文件存在,那么文件名就会被写入立即窗口。 


5. 在同一个模块里输入另外一个过程: 


Sub GetFiles() 


     Dim nfile As String 


     Dim nextRow As Integer  'next row index 


     nextRow = 1 


     With Worksheets("Sheet1").Range("A1") 






          nfile = Dir("C:\", vbNormal) 


          .Value = nfile 


          Do While nfile <> "" 


              nfile = Dir 


              .Offset(nextRow, 0).Value = nfile 


              nextRow = nextRow + 1 


          Loop 


     End With 


End Sub 


过程GetFiles获取C盘根目录下的所有文件名并且将每个文件名写入工作表。 






4.获得文件修改的日期和时间(FileDateTime 函数) 






如果你的过程需要知道某文件的最后修改的时间的话,可以使用函数FileDateTime: 


FileDateTime(文件路径名) 


文件路径名是个字符串,明确你要用的文件,并且需要包括驱动和文件夹的名称。该函数返回某文 


件的日期和时间印记。日期和时间的格式取决于视窗控制面板的原始设置。 


我们在立即窗口里来练习使用该函数: 


1. 在立即窗口里输入: 


?FileDateTime("C:\config.sys") 


回车后,VB返回下述格式的日期和时间 






                                         137 




----------------------- Page 155-----------------------


5/4/2001 10:52:00 AM 


要分开获取日期和时间时,可以将函数FileDateTime作为函数DateValue或TimeValue的参数来使 


用。例如: 


?DateValue(FileDateTime("C:\config.sys")) 






?TimeValue(FileDateTime("C:\config.sys")) 


2. 在立即窗口里将下述语句在一行输入: 


If DateValue(FileDateTime("C:\config.sys"))< Date then Debug.Print "This file was not 






modified today.” 


Date函数返回当前系统日期,也是视窗控制面板的日期/时间对话框里设定的。 






5.获得文件大小(FileLen 函数) 






如果你需要检查某文件是否能够存在某磁盘上,那么你应该按照下述方式使用FileLen函数: 


FileLen(文件路径名) 


FileLen函数一字节方式返回文件的大小。如果该文件已打开,那么VB将返回该文件最后一个保存 


时的大小。 


假设你想要获取Windows目录下进行配置设置的所有文件的总大小: 


1. 在当前工程里插入新模块,并重命名为FileLenFunction 


2. 在代码窗口了输入过程TotalBytesIni: 


Sub TotalBytesIni() 


     Dim iniFile As String 


     Dim allBytes As Long 


     iniFile = Dir("C:\WINDOWS\*.ini") 


     allBytes = 0 


     Do While iniFile <> "" 






          allBytes = allBytes + FileLen("C:\WINDOWS\" & iniFile) 


          iniFile = Dir 


     Loop 


     Debug.Print "Total bytes: " & allBytes 


End Sub 






6.返回和设置文件属性(GetAttr 函数和 SetAttr 函数) 






文件和文件夹具有类似“只读”,“隐藏”,“系统”和“档案”的特点。这些特点就是属性。可以使 


用GetAttr函数来获得文件或文件夹的属性。该函数的唯一参数就是文件或文件夹路径名: 


GetAttr(文件路径名) 


上面的函数返回一个整数,代表下面显示的常量中的一个或多个常量之和。 


表8-2 文件和文件夹属性 


   常量                      数值            属性名称 


   vbNormal                0             普通文件(没有设置其它属性) 


   VbReadOnly              1             不可修改的文件或文件夹 


   vbHidden                2             在普通设置下不可见的文件或文件夹 


   vbSystem                4             系统文件 


   vbDirectory             16            对象为一个目录 


   vbArchive               32            档案(在最后一次备份后,该文件被修改) 






要知道某文件是否具有上述的属性,可以使用AND运算符来比较GetAttr函数的结果和常量数值。如 


果函数返回一个非零数值,那么该文件或文件夹具有和你测试的属性一样的属性。 


C:\MsDos.sys的属性是什么呢?你可以在立即窗口里快速获得: 


?getattr("C:\MsDos.sys") AND vbReadOnly 









?getattr("C:\MsDos.sys") AND vbHidden 






                                     138 




----------------------- Page 156-----------------------









?getattr("C:\MsDos.sys") AND vbSystem 









?getattr("C:\MsDos.sys") AND vbArchive 






32 


现在,我们来将这些信息一起放在一个过程里: 


1. 插入新模块,并重命名为GetAttrFunction 


2. 输入下述过程GetAttributes: 


Sub GetAttributes() 


     Dim attr As Integer 


     Dim msg As String 


     attr = GetAttr("C:\MSDOS.SYS") 


     msg = "" 


     If attr AND vbReadOnly Then msg = msg & "Read-Only (R)" 






     If attr AND vbHidden Then msg = msg & Chr(10) & "Hidden (H)" 






     If attr AND vbSystem Then msg = msg & Chr(10) & "System (S)" 






     If attr AND vbArchive Then msg = msg & Chr(10) & "Archive (A)" 


     MsgBox msg, , "MSDOS.SYS" 


End Sub 


3. 当你运行上面的过程时,你将看到如图8-1的信息框 






图8-1 使用GetAttr函数可以获得任何文件的属性 


GetAttr函数的相反函数是SetAttr函数,它允许你设置一个文件或文件夹的属性。语法如下: 


SetAttr 文件路径名, 属性 


文件路径名确定你要设置的文件或文件夹,第二个参数,属性,是一个或多个你要设置的属性常量。 


参见表8-1本章前面介绍的常量清单。 


假设你有一个叫做“C:\stamps.txt”的文件,并且要设置两个属性,“只读”和“隐藏”。在立即 


窗口里输入下述指令来设置文件属性(可以找个你硬盘上存在的文件来试验): 






SetAttr "C:\stamps.txt", vbReadOnly + vbHidden 


技巧8-2 调用SetAttr语句 


你不能给打开的文件设置属性,在使用SetAttr函数之前,你必须关闭该文件。 






7.更改缺省文件夹或驱动器(ChDir 语句和 ChDrive 语句) 






使用ChDir语句,你可以轻易更改缺省文件夹,例如: 


ChDir Path 


在上面的语句中,Path是新的缺省文件夹名称。Path可以包含驱动器名称。如果Path没有包括驱动 


名称,那么缺省文件夹将会更改为当前驱动。当前驱动不变。 


假设缺省文件夹为“C:\DOS”,语句: 


ChDir "D:\MyFiles" 


将缺省文件夹更改为“D:\MyFiles”,然而,当前驱动仍然是C盘。 


要更改当前驱动的话,你就应该使用ChDrive语句,按如下格式: 


ChDrive 驱动 


“驱动”是你将要设置的新的缺省驱动名称。例如,在立即窗口里输入下述指令将缺省驱动设置为 


D驱或者E驱: 






                                      139 




----------------------- Page 157-----------------------


ChDrive "D" 


或者 


ChDrive "E" 


如果你指向一个并不存在的驱动,你就会看到一个信息框“设备不可用” 






8.创建和删除文件夹(MkDir 语句和 RmDir 语句) 






依照下面的MkDir语句语法,你可以创建一个新文件夹: 


MkDir Path 


Path明确你要创建的新文件夹名称。如果你没有写驱动器的名称的话,VB就将在当前的驱动上创建 


新文件夹。现在,我们来看几个例子: 


1. 在立即窗口里输入指令,在C盘上创建一个叫“Mail”的文件夹: 


MkDir "C:\Mail" 


2. 将缺省文件夹更改为“C:\Mail”: 


ChDir "C:\Mail" 


3. 获取当前文件夹名称: 


?CurDir 


使用RmDir函数来删除不需要的文件夹。该函数的语法如下: 


RmDir Path 


Path明确你要删除的文件夹名称。Path可以包含驱动名称,如果你忽略了驱动名称,那么VB就会试 


图删除当前驱动下的相同名称的文件夹,如果存在的话;否则,VB将显示错误信息:“路径未找到” 


4. 删除刚才创建的文件夹C:\Mail: 


RmDir "C:\Mail" 


技巧8-3 RmDir移除空文件夹 


如果文件夹里有东西,你不可以删除它(使用RmDir)。你应该先用Kill语句删除这些文件(在本章 


后面讨论) 






9.复制文件(FileCopy 语句) 






使用FileCopy语句,可以在文件夹之间复制文件: 


FileCopy 来源, 目的地 


该语句的第一个参数是文件来源,明确你要复制的文件名称,该名称可以包含驱动名称。第二个参 


数是复制的目的地,可以包括驱动和文件夹的地址。两个参数都是必须的。假设你要将用户确定的 


一个文件复制到一个叫做“C:\Abort”的文件夹,下面的过程示范如何完成它: 


Sub CopyToAbort() 


     Dim folder As String 


     Dim source As String 


     Dim dest As String 


     Dim msg1 As String 


     Dim msg2 As String 


     Dim p As Integer 


     Dim s As Integer 


     Dim i As Long 


     On Error GoTo ErrorHandler 


     folder = "C:\Abort" 


     msg1 = "The selected file is already in this folder." 






     msg2 = "was copied to" 


     p = 1 


     i = 1 


     ' get the name of the file from the user 从用户处获取文件名称 


     source = Application.GetOpenFilename 






     ' don’t do anything if cancelled 如果取消则不进行任何操作 


     If source = "False" Then Exit Sub 


                                      140 




----------------------- Page 158-----------------------


     ' get the total number of backslash characters "\" in the source 获取文件来源字符 


     串中的反斜杠数 


     ' variable’s contents 


     Do Until p = 0 


          p = InStr(i, source, "\", 1) 


          If p = 0 Then Exit Do 


          s = p 


          i = p + 1 


     Loop 


     ' create the destination file name 创建目的文件名称 


     dest = folder & Mid(source, s, Len(source)) 






     ' create a new folder with this name 创建同名文件夹 


     MkDir folder 


     ' check if the specified file already exists in the 检查该文件是否在目的地已经存 


     在 


     ' destination folder 


     If Dir(dest) <> "" Then 


          MsgBox msg1 


     Else 


     ' copy the selected file to the C:\Abort folder 复制所选文件到文件夹“C:\Abort” 


     FileCopy source, dest 






     MsgBox source & " " & msg2 & " " & dest 


     End If 


     Exit Sub 


ErrorHandler: 


     If Err = "75" Then 


          Resume Next 


     End If 


     If Err = "70" Then 


          MsgBox "You can’t copy an open file." 


          Exit Sub 


     End If 


End Sub 


过程CopyToAbort使用了Excel应用程序的方法GetOpenFilename从用户那里获取文件名称。该方法 


导致弹出内置的打开对话框。使用该对话框,你可以在任何驱动的任何文件夹里选择任何文件。如 


果用户取消了,VB就返回值“False”并且程序结束。如果用户选取了某个文件并且点击了打开, 


那么该选中的文件就会赋值到变量source。因为复制的目的,你只需要文件名称(而不需路径名), 


所以Do…Until循环用来找到最后一个反斜杠(“\”)在变量source里的位置。 


接下来,VB给FileCopy语句的第二个参数准备了一个字母字符串,并且将其赋值到变量dest。该变 


量储存的字符串是目标文件夹(C:\Abort)和用户指定的文件名前面加反斜杠连接起来的。函数 


MkDir创建了一个叫C:\Abort的文件夹,如果它不存在于C盘上的话。如果这样的文件夹已经存在的 


话,那么VB就需要去处理错误75了。这个错误会被在程序后面的错误处理代码捕获。注意,错误处 


理器是一代码片断,它用ErrorHandler带冒号标志。 


当VB遇到Resume Next语句时,就会继续执行过程里面导致错误的代码行下面的代码。这意味着语 


句MkDir folder不会被执行。在这之后,程序将检查被选择的文件是否已经存在于目的文件夹。如 


果文件在那,那么用户将收到储存于变量msg1里面的信息;如果文件不存在于目的文件夹并且该文 


件当前没有打开的话,VB就会将文件复制到指定的文件夹,并且用相应的信息通知用户。如果该文 


件被打开了,VB将遇到运行时间错误70,并且因此而运行ErrorHandler里面的相应指令。 


1. 在一名为FileCopyStatement的信魔窟里输入过程CopyToAbort 


2. 运行该程序几次,从不同的文件夹里选择文件 






                                       141 




----------------------- Page 159-----------------------


3. 试着复制该程序之前复制过的文件到文件夹C:\Abort 


4. 打开某个文件,并且在其开着的情况下试图用过程CopyToAbort来复制它 


5. 运行本章前面准备的过程MyFiles,在立即窗口里列出文件夹C:\Abort里面的内容 


注意,不要删除文件夹C:\Abort和你复制的文件,你将在下一节里面使用一个叫RemoveMe的VBA过 


程来同时删除文件和文件夹。 






10.删除文件(Kill 语句) 






你已经从前面的章节里知道了不能删除含有文件的文件夹,要从文件夹里面删除文件的话,可以使 


用下面的Kill语句: 


Kill 文件路径名 


文件路径名明确一个或多个你要删除的文件的名称,随你意,也可以将驱动器和文件夹名称包括在 


里面。你可以在文件路径名参数里使用通配符(*或?)来确保快速删除文件。你不能删除开启的文 


件。 


如果你是跟着前面的练习一步一步过来的,那么你的硬盘上应该有了文件夹C:\Abort和好几个文件 


了里面了。在下面的练习里,你将首先删除文件夹Abort里面的所有文件,然后再删除文件夹本身: 


1. 在当前工程里插入新模块,并重命名为KillStatement 


2. 在过程RemoveMe里输入代码,如下所示: 


Sub RemoveMe() 


     Dim folder As String 


     Dim myFile As String 


     ‘assign the name of folder to the folder variable 


     ‘notice the ending backslash "\" 


     folder = "C:\Abort\" 


     myFile = Dir(folder, vbNormal) 


     Do While myFile <> "" 


        Kill folder & myFile 


        myFile = Dir 


     Loop 


     RmDir folder 


End Sub 


3. 运行过程RemoveMe,当程序运行结束,点击Windows文件浏览器看看该文件夹是否已经被删除了。 






11.从文件读取和写入数据(Input/Output) 






你已经从前面的章节里知道了如何使用VBA打开一个电子表格,例如指令: 






Application.Workbooks.Open Filename:= "C:\Excel\Report.xls" 






打开位于文件夹C:\Excel里面的文件Report.xls。除了使用专门的应用程序打开文件之外,你如果 


也想要创建VBA过程能够打开其它类型的文件并使用它们的内容的话,你就应该学习一些关于被称 


为低级别的文件I/O(input/output)。接下来关于顺序,随机和二进制文件的章节将会带你直接接 


触你的数据。 






12.文件访问类型 






计算机使用的文件类型有三种: 


•  顺序访问文件是指按储存相同的顺序找回数据的文件。例如以CSV格式(逗号分割文本),TXT 


   格式(以Tab键分割的文本)或者PRN格式(以空格分隔的文本)储存的文件。顺序文件访问经 


   常用来写文本文件,例如错误日志,参数设定和报告。顺序文件有下列模式:Input, Output 和 


   Append。模式决定了文件打开后你如何使用它。 


•  随机访问文件是文本文件,它的数据以同等长度储存并在一个以逗号分割的区域了。随机访问 


   文件只有一个模式——Random 


•  二进制访问文件是图形文件和其它非文本文件。二进制文件只能够在Binary模式下访问。 






                                   142 




----------------------- Page 160-----------------------


13.使用顺序文件 






你的电脑硬盘上有成百上千的顺序文件。参数文件,错误日志,HTML文件以及所有类型的无格式文 


本文件都是顺序文件。这些文件以字母顺序在硬盘上储存。新文本行的开始以两个专门的字符表示, 


一个叫做carriage return (回车),另一个叫line feed(换行)。当你使用顺序文件时,你从文 


件的开头始,一个字符一个字符的向前移动,一行接一行,直到文件的结尾。顺序文件容易打开和 


操作,任何文本编辑器都可以。 


技巧8-4 什么是顺序文件? 


顺序文件就是访问它里面的记录时必须按它占据的顺序进行的文件,这意味着在你想访问第三个记 


录之前,你必须先访问第一个记录,接着是第二个记录。 


技巧8-5 使用Open语句打开文件 


当你使用顺序访问来打开一个文件时,该文件必须是已经存在的。 






14.读取储存于顺序文件里的数据 






我们来用一个已经在你电脑上的顺序文件并且在Excel VB编辑器窗口直接使用VBA来读取它的内 


容。要从一个文件读取数据,你就必须先使用Open语句打开该文件。这是它的语法: 






Open pathname For mode [Access access][lock] As [#]filenumber [Len=reclength] 


Open语句有三个必须的参数,它们是pathname, mode, 和 filenumber。上面的语法里,这三个参 


数前面都有用粗体显示的关键字。 


•  Pathname是你要打开的文件名称 


•  Pathname可以包括驱动器和文件夹名称 


•  Mode是个决定文件如何打开的关键字。顺序文件可以以下列模式之一来打开:Input, Output 或 


   Append。使用Input读文件,Output写文件,将覆盖任何存在的文件,以及Append来写入文件, 


   同时附加上任何已经存在的信息。 


•  Access是决定决定文件读写的关键字,Access可以是:Shared(共享),Lock Read(锁定读), 


   Lock Write(锁定写)或Lock Read Write(锁定读写)。 


•  Lock决定了哪些文件的操作是允许其它过程进行的。例如,如果某文件是在网络环境下打开的, 


   “锁定”决定了其他人如何访问它。下述锁定关键字是可以用的:Read, Write 或者 Read Write。 


•  Filenumber是从1到511的数字,该数字用来指向顺序操作中的文件。通过使用VB内置函数 


   FreeFile,你可以获得一个唯一的文件号码。 


•  Open语句里的最后一个成员reclength明确顺序文件里总字符数,或者是随机文件里记录大小。 


考虑一下前面的例子,为了读取数据,要打开C:\Autoexec.bat或者其它顺序文件,你应该使用下 


面的指令: 


Open "C:\Autoexec.bat" For Input As #1 


如果某文件已经打开输入了,那么从它读取数据。在打开一格顺序文件后,你就可以使用下面的语 


句读取它的内容:Line Input #或者 Input # 或者使用Input 函数。 






15.逐行读取文件 






使用下面的语句来逐行读取Autoexec.bat或者其它任何顺序文件里的内容: 






Line Input #filenumber, variableName 






#filenumber是用Open语句打开文件时使用的数字,variableName是个String或者Variant变量,用 


来储存读取的行。 


Line Input #语句仅读取一开启顺序文件里的一行并且储存在一变量里。记住,Line Input # 语 


句一次读取顺序文件里的一个字符,直到它遇到回车字符(Chr(13))或者回车-换行字符(Chr(13) 


& Chr(10))。这些字符(回车,换行)在读取过程中返回的文本里是会忽略掉的。 


接下来的过程ReadMe示范如何使用Open和Line Input #语句逐行读取Autoexec.bat文件的内容。试 


试用同样的方法来读取其它顺序文件。 


1. 在当前工程里面插入新模块并重命名为SeqFiles 


2. 输入下列过程ReadMe: 


Sub ReadMe() 


     Dim rLine As String 






                                  143 




----------------------- Page 161-----------------------


     Dim i As Integer ' line number 


     i = 1 






     Open "C:\Autoexec.bat" For Input As #1 


     ' stay inside the loop until the end of file is reached 






     Do While Not EOF(1) 


           Line Input #1, rLine 


           MsgBox "Line " & i & " in Autoexec.bat reads: " _ 






           & Chr(13) & Chr(13) & rLine 


           i = i + 1 


     Loop 


     MsgBox i & " lines were read." 


     Close #1 


End Sub 


3. 按下F8,逐句运行该过程 


为了读取内容,过程ReadMe将文件Autoexec.bat在模式Input里作为文件号码1打开。Do…While循 


环告诉VB一直执行循环里面的语句,直到到达文件结尾。文件的结尾由函数EOF的结果决定。 


EOF函数当下个要读取的字符已经过了文件结尾时,返回逻辑值True。注意,EOF要求一个参数—— 


你要检查的打开了的文件号码,是前面Open语句使用的同一个数字。使用EOF函数来确保VB不会超 


出文件结尾处。 


Line Input # 语句将每行内容储存于变量rLine里,然后,信息框显示行号和它的内容。之后如果 


函数EOF的结果还是为假(还未到达文件结尾处)的话,VBA给行计数器增加1,并且开始读取下一 


行。当函数EOF结果为真是,VB就会退出循环。在VBA结束前,还会再运行两条语句,显示读取行的 


总数,以及关闭该打开的文件。 






16.从顺序文件中读取字符 






假设你的程序需要检查文件Autoexec.bat里出现了多少个冒号,你可以使用函数Input来返回特定 






的字符数,而不必读取整行。接下来,If语句用来比较获取的字符和你寻找的字符。在写过程之前, 


我们来看看函数Input的语法: 


Input(number, [#]filenumber) 


Input函数的两个参数都是必须的,number明确你要读取的字符数,而filenumber是Open语句用来 


打开文件的同一个数字。Input函数返回所有读取的字符,包括逗号,回车,文件结束字符,引号 


和前导空格。 


1. 在SeqFile模块里输入下述过程Colons: 


Sub Colons() 


     Dim counter As Integer 


     Dim char As String 


     counter = 0 


     Open "C:\Autoexec.bat" For Input As #1 






     Do While Not EOF(1) 


           char = Input(1, #1) 


           If char = ":" Then 


           counter = counter + 1 


           End If 


     Loop 


     If counter <> 0 Then 






           MsgBox "Characters found: " & counter 


           Else 


           MsgBox "The specified character has not been found." 






     End If 


     Close #1 






                                         144 




----------------------- Page 162-----------------------


End Sub 


2. 逐句执行该过程 


3. 将冒号换成其它你想寻找的字符并且重新执行该程序。Input函数允许你返回顺序文件的任何字 


   符。如果你使用VB函数LOF作为Input函数的第一个参数时,你将能够快速地读取顺序文件里的 


   内容,而不需要在整个文件上循环。LOF函数返回一个文件上的字节数。每个字节对应了文本文 


   件里的一个字符。过程ReadAll将文件System.ini的内容读取到立即窗口里: 


Sub ReadAll() 


     Dim all As String 


     Open "C:\WINNT\System.ini.bat" For Input As #1 






     all = Input(LOF(1), #1) 


     Debug.Print all 


     Close #1 


End Sub 


除了将文件内容打印到立即窗口之外,你还可以将其读取到一个文本框并且放置到工作表中去(见 


图8-2): 


Sub WriteToTextBox() 


     Dim mysheet As Worksheet 


     Set mysheet = ActiveWorkbook.Worksheets(1) 






     On Error GoTo CloseFile 


     Open "C:\WINNT\System.ini" For Input As #1 


     mysheet.Shapes(1).Select 






     Selection.Characters.Text = Input(LOF(1), #1) 


     CloseFile: 


     Close #1 


End Sub 






图8-2 文件TDate.ini(译者:原文为System.ini)的内容显示在工作表中的文本框里 


在你运行上面的程序之前,你得在工作表里画一个文本框。注意,On Error GoTo CloseFile语句 


激活错误捕捉,如果错误在程序的执行过程中发生了,就会立即跳到CloseFile标签处,Close #1 


语句无论有无错误发生都会被执行。 






17.读取分隔文本文件 






在某些文本文件中(文件通常保存为CSV,TXT或PRN格式)输入在每行的数据由逗号,Tab或者空格 


分隔。这种类型的文件用Input # 语句可以比前面介绍的Line Input #语句读取更快些。Input # 


语句允许你从一个打开的文件中读取数据到好几个变量,该函数如下所示: 


Input #filenumber, variablelist 


Filenumber是用Open语句打开文件时的同一个号码,variablelist是一个以逗号分开的变量清单, 






                                        145 




----------------------- Page 163-----------------------


用来储存读取的的数据。你不能使用数组或对象变量,然而,你可以使用用户定义的变量(这种变 


量将在本章后面介绍)。 


下面的例子是一个用逗号分隔数据的顺序文件: 


Smith,John,15 


Malloney,Joanne,28 


Ikatama,Robert,15 


要读取该格式的文本的话,你必须给每个数据明确一个变量:姓,名和年龄。 


1. 打开一个新工作簿,并且输入下面的数据: 






2. 将文件保存为CSV格式在C:\Winners。Excel将显示信息告诉你,该格式文件不支持含有多个工 


   作表的工作簿。点击确定,只保存当前工作表。 


3. 输入下面的过程Winners: 


Sub Winners() 


     Dim lname As String, fname As String, age As Integer 






     Open "C:\Winners.csv" For Input As #1 


     Do While Not EOF(1) 


         Input #1, lname, fname, age 


         MsgBox lname & ", " & fname & ", " & age 






     Loop 


     Close #1 


End Sub 


4. 在运行过程Winners之前,你要确保该文件在指定的路径下,或者在程序里指定文件Winners.csv 


   的正确位置。 


上面的程序打开文件Winners.csv读取数据,并且建立了一个Do…While循环,在整个文件里运行直 


到文件的结尾。Input #1语句用来将每行的内容读取到三个变量:lname, fname和age,然后,一 


个信息框将这三个变量的内容显示出来。程序最后关闭文件Winners.csv。 






18.往顺序文件里写数据 






当你要往一个顺序文件里写入数据时,你应该以Append或者Output模式打开该文件。这些模式的区 






别解释如下: 


•  Append允许在一个现存文件的结尾处添加数据。例如,如果你以Append模式打开Readme.txt文 


   件,并且将文本“谢谢你阅读本文件”加到该文件,VB不会删除或者以任何方式改变该文件中 


   已经存在的文本,但是,会在文件的结尾处加上新的文本。 


•  Output 当你以Output模式打开一个文件时,VB将会将文件里的现存的数据删除,而且,如果 


   该文件并不存在的话,就会创建一个全新的文件。例如,如果你以Output模式打开文件 


   Readme.txt,并且试图往里面写数据的话,那么以前储存在该文件里的文本就会被删除掉。如 


   果你在写入数据之前没有备份该文件的话,那该失误的代价将会是非常大的。如果你想要用新 


   数据取代整个内容的话,就应该以Output模式打开该已存在的文件。 


这里有些例子,什么时候应该用Append,什么时候用Output: 


•  要在文件C:\Readme.txt后面添加新文本,按下面以Append模式打开该文本: 


Open "C:\Readme.txt" For Append As #1 






•  要在一个叫C:\Result.txt的全新文件里输入一些文本,那么以Output模式打开该文件: 


Open “C:\Result.txt” For Output As #1 


•  要取代现存文件C:\Winners.csv的内容,首先将原始文件备份一份,然后将原始文件以Output 






                                   146 




----------------------- Page 164-----------------------


   模式打开: 






FileCopy "C:\Winners.csv","C:\Winners.old" 






Open "C:\Winners.csv" For Output As #1 


技巧8-6 不可同时读写 


顺序文件必须分别打开来执行读和写的操作,你不可以同时执行这些操作。例如,在一个文件已经 


打开并且写入数据后,该文件必须先关闭,之后才能再打开来读取数据。 


技巧8-7 顺序文件的优势和劣势 


尽管顺序容易创建和使用,并且不回浪费空间,但是它们也有很多不好的地方。例如,要是不读一 


大部分文件内容的话,你是很难找到某个特定项目的。同时,文件的个别项目不容易改变或删除— 


—你必须重新写入整个文件。在有,在技巧8-6例说的,顺序文件必须分开进行读和写的操作。 






19.使用 Write # 和 Print # 语句 






既然打开一文本文件来写入数据的两种方法(Append或Output)你都已经知道了,那么是时候学习 


Write #和Print #语句了,它们让你将数据发送到文件。当你使用Input #语句从一个顺序文件读 


取数据的时候,通常可以使用Write #语句往该文件写数据,如下所示: 


Write #filenumber, [outputlist] 


Filenumber明确你正使用的文件的号码,它是Write #语句的唯一必须的参数。Outputlist是你要 


写入的文本。Outputlist可以是你要写入的单个文本字符,也可以是包含数据的变量清单。如果你 


只明确了文件号码,VB就会在打开的文件里写入一个空行。 


我们了准备一个文本文件,里面是三个人的名,姓,生日和兄弟姐妹的数目,演示数据是如何写入 


文件的: 


1. 在当前模块里输入过程DataEntry: 


Sub DataEntry() 


     Dim lname As String 


     Dim fname As String 


     Dim birthdate As Date 


     Dim s As Integer 


     Open "C:\My Documents\Friends.txt" For Output As #1 


     lname = "Smith" 


     fname = "Gregory" 


     birthdate = #1/2/63# 


     s = 3 


     Write #1, lname, fname, birthdate, s 


     lname = "Conlin" 


     fname = "Janice" 


     birthdate = #5/12/48# s = 1 






     Write #1, lname, fname, birthdate, s 


     lname = "Kaufman" 


     fname = "Steven" 


     birthdate = #4/7/57# 


     s = 0 






     Write #1, lname, fname, birthdate, s 


     Close #1 


End Sub 


上面的过程打开文件C:\My Documents\Friends.txt来写入数据。因为该文件还不存在于你的硬盘 


上,所以VB就创建了一个全新的文件并写入三个记录。写入文件的数据储存在变量上。注意,这些 


字符串由双引号分隔,而生日则有井号包围起来了。 


当你使用Windows记事本打开文件Friends.txt是,你将看到下述输入: 


"Smith","Gregory",#1963-01-02#,3 


"Conlin","Janice",#1948-05-12#,1 






                                       147 




----------------------- Page 165-----------------------


"Kaufman","Steven",#1957-04-07#,0 


注意,Write #语句自动在每个数据之间插入逗号并且将行结束字符(Chr(13) & Chr(10))放在每行 


文本的后面,以至于每行新纪录都从新的行开始。在上面的例子里面,每行文本显示一条记录—— 


每条记录以姓开始,以同胞数目结束。 


如果你想要将数据显示在一列中,而不是用逗号分隔数据,那么就使用Print #语句。例如,如果 


将上面的程序DataEntry里的Write #语句用Print #语句代替的话,那么VB就会按下面的方式写入 


数据: 


Smith     Gregory   1/2/63    3 


Conlin    Janice    5/12/48   1 


Kaufman   Steven    4/7/57    0 


尽管Print #语句和Write #语句的语法一样,但是,Print #以一个准备打印的格式将数据写入顺 


序文件。清单里的变量可能用分号或者空格分隔。要打印多个空格的话,你就应该使用Spc(n)指令, 


这里n是空格数。类似地,要将数据输入到第五列的话,你就应该使用指令Tab(5)。 


我们来看一些格式例子: 


•  使用带逗号的Write #语句,往文件里输入空行 


Write #1, 


•  在第五列输入文本“fruits” 


Write #1, Tab(5); “fruits” 


•  用五个空格分隔开单词“fruits”和“vegetables” 


Write #1, “fruits”; Spc(5); “vegetables” 






20.操作随机文件 






当某文件包含结构数据时,就以随机模式打开它。以随机模式打开文件让你能够: 


•  同时读写 


•  快速访问某特别记录 


在随机文件里,所有记录都是等长度的,并且每条记录都有相同数目的固定大小区域。记录或者区 


域的长度必须在文件写入数据之前就确定。如果写入某区域的字符串长度小于该区域的大小,那么 


VB就会自动在该字符串后面加空格来填充区域。如果写入的文本比区域长度长的话,超出的字符就 


不会被写入。 


要知道如果操作随机文件,你现在就需要创建一个小数据库用作外语学习。该数据库将包含由两个 


区域组成的记录,储存英语词组和其外语等同语。 


技巧8-8 随机文件是什么? 


随机文件是储存的记录可以随机访问的文件,这意味着随机文件里的任何记录都可以读取,而不必 


读取它之前的每条记录。 






21.创建用户定义的数据类型 






除了第三章里介绍的内置数据类型之外,VB允许你在模块的上面使用Type…End Type语句定义一个 


非标准的数据类型。该非标准数据类型也经常成为用户自定义的数据类型。用户自定义数据类型可 


以包括各种数据类型(字符串,整型,日期等等)的内容。当你使用随机访问的文件时,你经常要 


创建一用户定义的变量,因为,该变量使你可以轻易地访问个别记录。 


1. 在当前工程里插入新模块并且重命名为RandomFiles 


2. 在模块上面,紧接着Option Explicit语句下面,输入下述类型定义: 


Option Explicit 


' define a user-defined type 


Type Dictionary 


     en As String * 16 ' English word up to 16 characters 






     sp As String * 20 ' Spanish word up to 20 characters 


End Type 


用户定义的名为Dictionary的类型包括两个声明为String(字符串)的项目,并且有特定的大小。 


成员en可以接受最多16个字符,第二个项目sp的大小不能超过20个字符。如果你将这两个成员的长 


度加起来,那么记录长度将为36(16+20)。如果模块了已经有了Option Explicit语句的话,你就 


                                   148 




----------------------- Page 166-----------------------


不必再输入它了。 


3. 输入下面的过程EnglishToSpanish 


Sub EnglishToSpanish() 


     Dim d As Dictionary 


     Dim RecNr As Long 


     Dim choice As String 


     Dim totalRec As Long 


     RecNr = 1 


     'open the file for random access 打开文件作随机访问 






     Open "Translate.txt" For Random As #1 Len = Len(d) 


     Do 


          ' get the English word 活动英文词语 


          choice = InputBox("Enter an English word", "ENGLISH") 


          d.en = choice 


          ' exit the loop if cancelled 如取消则退出循环 


          If choice = "" Then Exit Do 






          choice = InputBox("Enter the Spanish equivalent for " _ 


          & d.en, "SPANISH EQUIVALENT " & d.en) 






          If choice = "" Then Exit Do 


          d.sp = choice 


          ' write to the record 写入记录 


          Put #1, RecNr, d 


          ' increase record counter 增加记录计数器 


          recNr = recNr + 1 


     Loop Until choice = "" 'ask for words until Cancel 询问词语直到取消 


     totalRec = LOF(1) / Len(d) 


     MsgBox "This file contains " & totalRec & " record(s)." 


     ' close the file 


     Close #1 


End Sub 


过程EnglishToSpanish开始时,声明四个变量,变量d声明为用户定义的类型Dictionary。该类型 


在 前 面 就 用 Type 语 句 声明 了 ( 见 第 二 步 )。 在 给 变 量 RecNr 赋 予 了 初 始 值 之 后 , VB 


打 开 文 件 


Translate.txt,并且将其作为文件编码1随机访问。指令Len(d)告诉VB每条记录的大小为36字符。 


接下来VB执行Do…Until循环里面的语句,直到你取消。循环里的第一条语句提示你输入一个英语 


单词,并且将其赋予变量choice,然后该值被传递给用户定义d的第一个成员(d.en)。 


一旦你停止输入数据,VB就会退出Do循环,并且执行程序里的最后的语句计算和显示文件里的记录 


总数。最后一条语句将文件关闭。如果你输入了英文词语并点击确定,那么下个对话框就会提示你 


输入外语等同语。当然,如果你决定现在就退出的话,VB就会跳出循环并且继续剩下的语句。如果 


一切正常,你输入了外语翻译,那么VB就会将它赋予变量choice并且传递给用户自定义变量d的第 


二个成员(d.sp),接下来,VB使用下述语句将整条记录写入到文件里: 


Put #1, recNr, d 


写入第一条记录后,VB会给记录计数器增加1,然后重复循环里的语句。过程EnglishToSpanish允 


许你在你的字典里输入任意多条记录。当你退出提出词语时,过程使用LOF和Len函数来计算文件里 


的总记录数。VB在显示信息后关闭该文本文件(Translate.txt)。 


创建随机文件仅仅是个开始,接下来,过程VocabulartDrill示范如何使用一个开启的随机文件的 


记录。这里,你将学习让你快速找到你文件中适合的数据的语句。 


技巧8-9 理解Type语句 


Type命令允许你创建一个自定义组,包括混合的变量类型,称为“用户自定义数据类型”。Type语 


句通常用于随机文件,将信息作为区域储存为固定大小的记录。我们可以将随机文件用的区域使用 


Type语句集中成为一个用户自定义,而不必为每个区域都声明一个变量。例如,如下所示定义一个 






                                      149 




----------------------- Page 167-----------------------


包含三个区域的记录: 


Type MyRecord 


country As String * 20 


city As String * 14 


rank As Integer 


End Type 


一旦定义了类型,你必须给使用这种类型的变量名称: 


Dim myInfo As MyRecord 


使用变量名称后面加上句号和内部变量可以访问内部变量(country, city, rank),例如,要明确 


城市,输入: 


MyInfo.city = "Warsaw" 


4. 在过程EnglishToSpanish下面输入下面显示的过程VocabularDrill,代码的介绍在其后面。 


Sub VocabularyDrill() 


      Dim d As Dictionary 


      Dim totalRec As Long 


      Dim recNr As Long 


      Dim randomNr As Long 


      Dim question As String 


      Dim answer As String 


      ' open a random access file 打开随机访问文件 


      Open "Translate.txt" For Random As #1 Len = Len(d) 






      ' print the total number of bytes in this file 打印本文件的总字节数 


      Debug.Print "There are " & LOF(1) & " bytes in this file." 






      ' find out and print out the total number of records 找到并且打印总记录数 


      recNr = LOF(1) / Len(d) 






      Debug.Print "Total number of records: " & recNr 


      Do 


            ' get a random record number 获取随机记录数 


            randomNr = Int(recNr * Rnd) + 1 


            Debug.Print randomNr 


            ' find the random record 找到该随机记录 


            Seek #1, randomNr 


            ' read the record 读取记录 


            Get #1, randomNr, d 


            Debug.Print Trim(d.en); " "; Trim(d.sp) 






            ' assign answer to a variable 将答案赋予变量 


            answer = InputBox("What's the Spanish equivalent?", d.en) 






            ' finish if cancelled 如取消则介绍 


            If answer = "" Then Close #1: Exit Sub 


            Debug.Print answer 


            ' check if the answer is correct 检查答案是否正确 


            If answer = Trim(d.sp) Then 


               MsgBox "Congratulations!" 


            Else 


               MsgBox "Invalid Answer!!!" 


            End If 


            ' keep on asking questions, until Cancel is pressed 不断提问,直到按下取消 


      Loop While answer <> "" 


      ' close file 关闭文件 


      Close #1 






                                            150 




----------------------- Page 168-----------------------


End Sub 


声明变量之后,过程VocabularyDrill打开一个随机访问文件,并且告诉VB每个记录的长度Len = 


Len(d),接下来,在立即窗口里打印文件的总字节数和总记录数。字节数是由语句LOF(1)返回的。 


记录数是总字节数(LOF)除以一个记录的长度——Len(d)。接下来,VB执行循环里的语句直到按 


下Esc键或者取消按钮。循环里的第一条语句将函数Rnd的结果赋予变量randomNr。接下来的语句将 


这个数字写入立即窗口,指令Seek #1, randomNr在开启的文件中移动光标到变量randomNr明确的 


记录处,在下来的指令读取找到的记录内容。要在打开的随机访问文件中读取数据,你必须使用Get 


语句。指令: 


Get #1, randomNr, d 


告诉VB要读取的记录号码(randomNr)以及要读取数据的变量(d)。随机文件中的第一个记录在位 


置1,第二个记录在位置2,依次类推。忽略记录号码会导致VB读取下一个记录。然后,用户定义的 


类型字典的两个成员都被写入了立即窗口。函数Trim(d.en)和Trim(d.sp)将读取的记录前后可能含 


有的空格。接下来,VB显示信息,提示用户提供显示单词的外语等同语。该单词赋予变量answer, 


如果你按下Esc而不是点击确定的话,VB就会关闭文件并且接受程序,否则,VB将打印你的答案到 


立即窗口,并且通知你,你的答案是否正确。当你要退出单词训练程序,随时可以按下Esc或者点 


击对话框的取消按钮。 


如果你决定继续并且点击了确定按钮,程序就会产生一个新随机号码,并且会找回一个英语单词并 


且问你相对应的西班牙译语。 


你可以修改该过程VocabularyDrill,因此你可以将每个不正确翻译的单词写到工作表。同样,你 


也许想要将文件Translate.txt里的所有记录到写到工作表里,这样你就总可以知道你的字典内容。 


你可以在本书带的CD里找到这两个程序。 






图8-3 在记事本里打开随机文件的内容 






图8-4 试图用Microsoft Excel打开随机文件的内容。注意,Excel正确的认识了原始的数据类型— 


—随机文件里的数据是固定宽度的。 


技巧8-10 随机文件的优势与劣势 


不想顺序文件,随机文件里的数据可以被很快地访问,而且,这些文件在往里面写信息和读信息期 


间不需要关闭文件。随机访问文件不必按顺序读写。因为它们的记录和区域都有固定的长度,不管 


储存的字符有多少,使用的字节数总是一样的,因此,如果有些区域是空的或者比声明的区域短时, 






                                   151 




----------------------- Page 169-----------------------


就会浪费许多空间。 






22.操作二进制文件 






不象随机文件那样以固定长度储存数据,二进制文件是一些长度变化的记录的集合。例如,文件包 


含的第一个记录可以使10个字节,第二个记录可以只有5个字节,而第三个却可以使15个字节。这 


种储存数据的方法节省很多的硬盘空间,因为VB不需要在要储存的字符串后面加上多余的空格来确 


保它们有相同的长度(象往随机文件里写数据那样),在二进制文件里没有空间浪费。这就不奇怪 


二进制文件比前面所讲的两种文件占用的硬盘空间要少。正如随机文件,二进制文件也可以打开同 


时进行读和写的操作。然而,因为二进制文件里的记录是不同长度的,所以,这些文件的操作是更 


苦难一些的。要找回正确的数据的话,你就必须将每个区域和记录的大小信息储存起来。 


你将使用下述四种语句来操作二进制文件: 


•  使用Get语句来读取数据 


•  Put语句允许你往二进制文件输入新数据 


•  Loc语句返回所读的最后字节数(在随机文件里,Loc语句返回最后所读记录的数字) 


•  Seek语句将光标移动到文件中合时的位置。 


为了快速掌握上面语句的使用,我们来打开立即窗口,并且将下面表格里左边的指令输入到立即窗 


口。本练习的目的是在一个叫做MyData.txt文件里输入你的姓和名,然后再找回你输入的数据。 






   立即窗口输入代码                           解释 


   Open "MyData.txt" For Binary As #1 打开文件“MyData.txt”作为文件编号1来作二 


                                      进制访问 


   MsgBox "Total bytes: " & LOF(1)    显示打开文件的字节数(该文件现在为空) 


   fname = "Julitta"                  给变量fname赋值 


   ln = len(fname)                    将储存于变量fname的字符串长度赋予变量In 


   Put #1, , ln                       将变量In的内容放置在二进制文件的下一个字 


                                      节 


   MsgBox "The last byte: " & LOC(1)  显示最后一个字节的位置 


   Put #1, , fname                    在下一个位置放置变量fname的内容 


   lname = "Korol"                    给变量lname赋值 


   ln = len(lname)                    将储存于变量lname的字符串长度赋予变量In 


   Put #1 , ,ln                       将变量In的数值输入到二进制文件的下一个字 


                                      节 


   Put #1,,lname                      在下一个位置放置变量lname的内容 


   MsgBox "The last byte: " & LOC(1)  显示最后一个字节的位置 


   Get #1,1, entry1                   读取第一个字节位置的数值并将其赋予变量 


                                      entry1. 


   MsgBox entry1                      显示变量entry1的内容 


   Get #1, , entry2                   读 取 下 一 个 位 置 的 数 值 并 将 其 赋 予 变 量 


                                      entry2. 


   MsgBox entry2                      显示变量entry2的内容 


   Get #1, , entry3                   读 取 下 一 个 位 置 的 数 值 并 将 其 赋 予 变 量 


                                      entry3. 


   MsgBox entry3                      显示变量entry3的内容 


   Get #1, , entry4                   读 取 下 一 个 位 置 的 数 值 并 将 其 赋 予 变 量 


                                      entry4. 


   MsgBox entry4                      显示变量entry4的内容 


   Debug.Print                        将所有数据打印在立即窗口 


   entry1;entry2;entry3;entry4 


   7 Julitta 5 Korol                  立即窗口里显示的上条指令的结果 


   Close #1                           关闭文件 


                                  152 




----------------------- Page 170-----------------------


注意,上面的质量可以在CD里的过程EnterAndDisplay里找到。 


当往二进制文件输入数据时,请遵循下述指导: 


•  在往二进制文件写入字符串之前,将该字符串的长度赋予一个整型变量,通常可以使用下述代 


   码块: 


字符串长度 = Len(变量名称) 


Put #1, , 字符串长度 


Put #1, , 变量名称 


•  当你从二进制文件读取数据时,先得读取该字符串长度,然后才是字符串内容。可以使用Get 


   语句和String$函数来实现: 


Get #1, , 字符串长度 


变量名称=String(字符串长度, " ") 


Get #1, , 变量名称 


技巧8-11 二进制文件的优势与劣势 


与顺序文件和随机文件相比,二进制文件是最小的,因为它使用变化长度的记录,可以保存硬盘空 


间。和随机访问文件一样,你可以同时读写二进制文件。二进制文件的一个最大的不好之处就是你 


必须要准确地知道你要找回或者要操作的数据是如何储存在文件里的。 






23.操作文件和文件夹的时髦方法 






在你的电脑上有一个被隐藏的宝贝叫做Windows Scripting Host(WSH视窗脚本主机),它允许你创 


建一些程序,可以控制视窗操作系统和它的应用程序,以及从操作系统找回信息。WSH是一种ActiveX 


控件,可以在文件Wshom.ocx里找到。如果你正在使用Windows 95,98,NT5.0,2000,XP或者IE4, 


5或者6的话,该文件就会自动安装在Windows System32文件夹里面。 


WSH是一种脚本语言。脚本语言是指可以自动运行的一套命令。可以使用Command Scripting Host 


(Cscript.exe)从命令提示,或者使用Windows Scripting Host (Wscript.exe)从视窗直接创建或 


者运行脚本。在本章接下来的本分,你将学习WSH如何和VBA结合工作的。 


WSH有它自己的对象层次。使用CreatObject函数,你可以在VBA过程里引用WSH对象。在开始编写使 


用WSH的VBA过程之前,我们来看看你将能控制的一些对象。 






                                   153 




----------------------- Page 171-----------------------


图8-5 WSH是一个ActiveX控件,用来创建一些进行简单或复杂操作的脚本,而这种工作在早前的 


MS-DOS操作系统里是有Writing batch文件(.bat)来完成的 


1. 在VB编辑器窗口,选择“工具”-“引用” 


2. 在引用对话框,找到并选择Microsoft Scripting Runtime 






图8-6 对Microsoft Scripting Runtime创建引用 


3. 现在,按下F2打开对象浏览器 






                                    154 




----------------------- Page 172-----------------------


4. 在“所有库”的下拉列表里选择“Scripting”。你将看到WSH库里面的部分对象列表。WSH让你 


   轻易的获得一些问题的答案,例如“在哪个硬盘上我可以找到某个文件?”(GetDrive方法), 


   “某文件的扩展名是什么?”(GetExtensionName方法),“该文件最后一次修改在什么时候?” 


   (DateLastModified属性)以及“在给定的硬盘上存在某个文件夹或者文件吗?”(FolderExists 


   和FileExists方法)。 






图8-7 创建对Microsoft Scripting Runtime的引用之后(见图8-6),对象浏览器显示了很多对象, 


让你使用硬盘,文件夹,文件和其它内容。 






24.使用 WSH 获取文件信息 






WSH有个对象叫做FileSystemObject,该对象有好几种方法来操纵文件系统。我们来看看你如何获 


取某个特定文件的信息: 


1. 在当前工程里插入一新模块,并重命名为WSH 


2. 在模块WSH里,输入下述过程FileInfo: 


Sub FileInfo() 


     Dim fs As Object 


     Dim objFile As Object 


     Dim strMsg As String 


     Set fs = CreateObject("Scripting.FileSystemObject") 






     Set objFile = fs.GetFile("C:\WINNT\System.ini") ‘ 译 者 : 有 的 可 能 是 


     C:\Windows\System.ini 


     strMsg = "File name: " & _ 


      objFile.Name & vbCrLf 


     strMsg = strMsg & "Disk: " & _ 


      objFile.Drive & vbCrLf 


     strMsg = strMsg & "Date Created:" & _ 






                                      155 




----------------------- Page 173-----------------------


       objFile.DateCreated & vbCrLf 






      strMsg = strMsg & "Date Modified:" & _ 






       objFile.DateLastModified & vbCrLf 


      MsgBox strMsg, , "File Information" 






End Sub 


上面显示的过程FileInfo使用VBA函数CreateObject来创建一个ActiveX对象(FileSystemObject), 


该对象提供访问电脑文件系统的路径 


Dim fs As Object 


Set fs = CreateObject("Scripting.FileSystemObject") 






上面的代码声明了一个对象变量,名为fs。然后使用函数CreateObject创建一个ActiveX对象并且 


将该对象赋予对象变量。上面程序的第二行代码 






Set objFile = fs.GetFile("C:\WINNT\System.ini"), 


创建和返回对C:、WINNT的System.ini文件对象的引用,并且将其赋值给对象变量objFile。你可以 


读取File对象的很多属性,例如,objFile.Name语句返回该文件的完整文件名,语句objFile.Drive 


返回该文件所处的硬盘名称,语句objFile.DateCreated和objFile.DateLastModified分别返回该 


文件的创建日期和最后一次修改日期。这个程序可以容易地修改成返回文件类型,属性和它的父文 


件夹的名称。请试图使用下述指令你自己修改该过程: objFile.Type, objFile.Attributes, 


objFile.ParentFolder以及 objFile.Size。在对象浏览器里面点击File对象,看看关于文件,你 


还可以学习到别的什么。 






25.FileSystemObjec 的方法和属性 






FileSystemObjedt是个ActiveX控件,提供了到计算机文件系统的访问。该对象提供了很多种方法, 






表8-3里面列出了其中的一些。 






    方法                                       描述 


    FileExists                               如果文件存在就返回True 


                                             Sub FileExists() 


                                             Dim fs As Object 


                                             Dim strFile As String 


                                             Set                   fs                   = 






                                              CreateObject("Scripting.FileSystemObject") 


                                             strFile = InputBox("Enter the full name of the 


                                              file:") 


                                             If fs.FileExists(strFile) Then 


                                             MsgBox strFile & " was found." 


                                             Else 


                                             MsgBox "File does not exist." 


                                             End If 


                                             End Sub 


    GetFile                                  返回一对象File 


    GetFileName                              返回带路径文件名 


    GetFileVersion                           返回文件版本 


    CopyFile                                 复制文件 


                                             Sub CopyFile() 


                                             Dim fs As Object 


                                             Dim strFile As String 


                                             Dim strNewFile As String 


                                             strFile = "C:\Hello.doc" 






                                             strNewFile = "C:\Program Files\Hello.doc" 


                                             Set                   fs                   = 






                                         156 




----------------------- Page 174-----------------------


                                               CreateObject("Scripting.FileSystemObject") 






                                               fs.CopyFile strFile, strNewFile 


                                               MsgBox "A copy of the specified file was 






                                               created." 


                                               Set fs = Nothing 


                                               End Sub 


MoveFile                                       移动文件 


DeleteFile                                     删除文件 


                                               Sub DeleteFile() 


                                               Dim fs As FileSystemObject 


                                               Set fs = New FileSystemObject 






                                               fs.DeleteFile "C:\Program Files\Hello.doc" 


                                               MsgBox "The requested file was deleted." 


                                               End Sub 


DriveExists                                    如给定硬盘存在则返回True 


                                               Function DriveExists(disk) 


                                               Dim fs As Object 


                                               Dim strMsg As String 


                                               Set                      fs                       = 


                                               CreateObject("Scripting.FileSystemObject") 






                                               If fs.DriveExists(disk) Then 


                                               strMsg = "Drive " & UCase(disk) & " exists." 






                                               Else 


                                               strMsg = UCase(disk) & " was not found." 






                                               End If 


                                               DriveExists = strMsg 


                                               ' run this function from the worksheet 






                                               ' by entering in any cell the following: 


                                               =DriveExists("E:\") 


                                               End Function 


GetDrive                                       返回对象Drive 


                                               Sub DriveInfo() 


                                               Dim fs, disk, infoStr, strDiskName 


                                               strDiskName = InputBox("Enter the drive 


                                               letter:", _ 


                                               "Drive Name", "C:\") 


                                               Set                      fs                       = 






                                               CreateObject("Scripting.FileSystemObject") 


                                               Set                     disk                      = 


                                               fs.GetDrive(fs.GetDriveName(strDiskName)) 






                                               infoStr = "Drive: " & UCase(strDiskName) & 


                                               vbCrLf 






                                               infoStr = infoStr & "Drive letter: " & _ 


                                               UCase(disk.DriveLetter) & vbCrLf 


                                               infoStr = infoStr & "Drive Type: " & 


                                               disk.DriveType & vbCrLf 


                                               infoStr = infoStr & "Drive File System: " & _ 






                                               disk.FileSystem & vbCrLf 


                                               infoStr = infoStr & "Drive SerialNumber: " & _ 






                                               disk.SerialNumber & vbCrLf 






                                           157 




----------------------- Page 175-----------------------


                                               infoStr = infoStr & "Total Size in Bytes: " & 






                                               _ 


                                               FormatNumber(disk.TotalSize / 1024, 0) & " Kb" 






                                               & vbCrLf 


                                               infoStr = infoStr & "Free Space on Drive: " & 






                                               _ 






                                               FormatNumber(disk.FreeSpace / 1024, 0) & " Kb" 






                                               & vbCrLf 


                                               MsgBox infoStr, vbInformation, "Drive 


                                               Information" 


                                               End Sub 


GetDriveName                                   返回一个含有硬盘名称或者网络共享名称的字符串 


                                               Function DriveName(disk) 


                                               Dim fs As Object 


                                               Dim strDiskName As String 


                                               Set                       fs                       = 


                                               CreateObject("Scripting.FileSystemObject") 


                                               strDiskName = fs.GetDriveName(disk) 






                                               DriveName = strDiskName 


                                               ' run this function from the Immediate window 






                                               ' by entering ?DriveName("D:\") 


                                               End Function 


FolderExists                                   如文件夹存在则返回True 


                                               Sub DoesFolderExist() 


                                               Dim fs As Object 


                                               Set                       fs                       = 






                                               CreateObject("Scripting.FileSystemObject") 






                                               MsgBox fs.FolderExists("C:\Program Files") 






                                               End Sub 


GetFolder                                      返回对象Folder 


                                               Sub FilesInFolder() 


                                               Dim fs As Object 


                                               Dim objFolder As Object 


                                               Dim objFile As Object 


                                               Set                       fs                       = 


                                               CreateObject("Scripting.FileSystemObject") 


                                               Set  objFolder  =  fs.GetFolder("C:\") 


                                               Workbooks.Add 


                                               For Each objFile In objFolder.Files 






                                               ActiveCell.Select 


                                               Selection.Formula            =        objFile.Name 


                                               ActiveCell.Offset(0, 1) _ 


                                               .Range("A1").Select 


                                               Selection.Formula            =        objFile.Type 


                                               ActiveCell.Offset(1, -1) _ 


                                               .Range("A1").Select 


                                               Next 


                                               Columns("A:B").Select 


                                               Selection.Columns.AutoFit 


                                               End Sub 






                                            158 




----------------------- Page 176-----------------------


GetSpecialFolder                             返回操作系统文件夹路径: 


                                             0 — 视窗文件夹 


                                             1 — 系统文件夹 


                                             2 — 临时文件夹 


                                             Sub SpecialFolders() 


                                             Dim fs As Object 


                                             Dim strWindowsFolder As String 


                                             Dim strSystemFolder As String 


                                             Dim strTempFolder As String 


                                             Set                      fs                      = 






                                             CreateObject("Scripting.FileSystemObject") 






                                             strWindowsFolder = fs.GetSpecialFolder(0) 






                                             strSystemFolder = fs.GetSpecialFolder(1) 


                                             strTempFolder = fs.GetSpecialFolder(2) 


                                             MsgBox strWindowsFolder & vbCrLf _ 


                                             & strSystemFolder & vbCrLf _ 


                                             & strTempFolder, vbInformation + vbOKOnly, _ 






                                             "Special Folders" 


                                             End Sub 


CreateFolder                                 创建文件夹 


                                             Sub MakeNewFolder() 


                                             Dim fs, objFolder 


                                             Set                      fs                      = 






                                             CreateObject("Scripting.FileSystemObject") 


                                             Set                  objFolder                   = 


                                             fs.CreateFolder("C:\TestFolder") 


                                             MsgBox "A new folder named " & _ 


                                             objFolder.Name & " was created." 


                                             End Sub 


CopyFolder                                   复制文件夹 


                                             Sub MakeFolderCopy() 


                                             Dim fs As FileSystemObject 


                                             Set fs = New FileSystemObject 


                                             If fs.FolderExists("C:\TestFolder") Then 






                                             fs.CopyFolder                   "C:\TestFolder", 


                                             "C:\FinalFolder" 


                                             MsgBox "The folder was copied." 


                                             End If 


                                             End Sub 


MoveFolder                                   移动文件夹 


DeleteFolder                                 删除文件夹 


                                             Sub RemoveFolder() 


                                             Dim fs As FileSystemObject 


                                             Set fs = New FileSystemObject 


                                             If fs.FolderExists("C:\TestFolder") Then 






                                             fs.DeleteFolder "C:\TestFolder" 


                                             MsgBox "The folder was deleted." 


                                             End If 


                                             End Sub 


CreateTextFile                               创建文本文件 






                                          159 




----------------------- Page 177-----------------------


    OpenTextFile                               打开文本文件 


                                               Sub ReadTextFile() 


                                               Dim fs As Object 


                                               Dim objFile As Object 


                                               Dim strContent As String 


                                               Dim strFileName As String 


                                               strFileName = "C:\WINNT\System.ini" 


                                               Set                    fs                    = 






                                               CreateObject("Scripting.FileSystemObject") 






                                               Set objFile = fs.OpenTextFile(strFileName) 






                                               Do While Not objFile.AtEndOfStream 


                                               strContent = strContent & objFile.ReadLine & 


                                               vbCrLf 


                                               Loop 


                                               objFile.Close 


                                               Set objFile = Nothing 


                                               ActiveWorkbook.Sheets(3).Select 


                                               Range("A1").Select 


                                               Selection.Formula = strContent 


                                               End Sub 






对象FileSystemObject只有一个属性,叫做Drives,它返回对硬盘驱动集合的引用。使用该属性, 


你可以查看一个电脑硬盘的清单,如下所示: 


Sub DrivesList() 


      Dim fs As Object 


      Dim colDrives As Object 


      Dim strDrive As String 


      Set fs = CreateObject("Scripting.FileSystemObject") 






      Set colDrives = fs.Drives 


      For Each Drive In colDrives 






           strDrive = "Drive " & Drive.DriveLetter & ": " 


           Debug.Print strDrive 


      Next 


End Sub 






26.对象 File 的属性 






对象File允许你访问某特定文件的所有属性,下面的代码创建了对对象File的引用: 






Set fs = CreateObject("Scripting.FileSystemObject") 






Set objFile = fs.GetFile(“C:\My Documents\myFile.doc”) 


在本章前面的过程FileInfo里你可以发现使用对象File的例子。 






    属性                           描述 


    Attributes                   返回文件属性(和本章前面介绍的VBA函数GetAttr比较一下) 


    DateCreated                  文件创建日期 


    DateLastAccessed             最后访问日期 


    DateLastModified             最后修改日期 


    Drive                        驱动器名称,后面带冒号 


    Name                        文件名 


    ParentFolder                 文件的父文件夹 






                                            160 




----------------------- Page 178-----------------------


    Path                     文件完整路径 


    Size                     以字节表示的文件大小(与本章前面介绍的VBA函数FileLen比较一 


                             下) 


    Type                     文件类型。这就是显示在Windows文件浏览器类型一列中的文本(例 


                             如,参数设置,应用程序,快捷方式) 






27.文件夹对象属性 






对象Folder提供了对所有文件夹属性的访问。下面的代码行创建了对对象Folder的引用: 






Set fs = CreateObject("Scripting.FileSystemObject") 


Set objFolder = fs.GetFolder(“C:\My Documents”) 






    属性                       描述 


    Attributes               文件夹属性 


    DateCreated              文件夹创建日期 


    Drive                    包含该文件夹的驱动器(译者:原文为Name of Folder) 


    Files                    文件夹中的文件集合 


                             Sub CountFilesInFolder() 


                             Dim fs, strFolder, objFolder, colFiles 






                             strFolder = InputBox("Enter the folder name:") 


                             If Not IsFolderEmpty(strFolder) Then 


                             Set fs = CreateObject("Scripting.FileSystemObject") 






                             Set objFolder = fs.GetFolder(strFolder) 


                             Set colFiles = objFolder.Files 






                             MsgBox "The number of files in the folder " & _ 


                             strFolder & "=" & colFiles.Count 


                             End If 


                             End Sub 


                             上面的过程调用函数IsFolderEmpty,该函数将在本表中的大小属性 


                             里讨论。 


    IsRootFolder             如果本文件夹为根文件夹则返回True 


    Name                     文件夹名称 


    ParentFolder             该文件夹的父文件夹 


    Path                     文件夹的完整路径 


    Size                     文件夹大小,以字节表示 


                             Function IsFolderEmpty(myFolder) 


                             Dim fs, objFolder 






                             Set fs = CreateObject("Scripting.FileSystemObject") 


                             Set objFolder = fs.GetFolder(myFolder) 






                             IsFolderEmpty = (objFolder.Size = 0) 


                             End Function 


    SubFolders               该文件夹中的子文件夹集合 


    Type                     文件夹类型(例如文件夹或回收站) 






28.驱动器对象属性 






对象Drive提供了访问到电脑或服务器上某驱动的属性。下述代码创建了对Drive对象的引用: 






Set fs = CreateObject("Scripting.FileSystemObject") 






Set objDrive = fs.GetDrive(“C:\”) 


在下面的表格里,你将看到好几个使用Drive对象的程序示例。 


                                       161 




----------------------- Page 179-----------------------


    属性                        描述 


    AvailableSpace            可用空间,字节表示 


    FreeSpace                 同AvailableSpace 


    DriveLetter               驱动器字母(没有冒号) 


    DriveType                 驱动器类型: 


                              0 — 未知 


                              1 — 可移动 


                              2 — 固定 


                              3 — 网络 


                              4 — CD驱动 


                              5 — RAM 


                              Sub CDROM_DriveLetter() 


                              Const CDROM = 4 


                              Dim fs, colDrives 






                              Set fs = CreateObject("Scripting.FileSystemObject") 


                              Set colDrives = fs.Drives 


                              For Each Drive In colDrives 


                              If Drive.DriveType = CDROM Then 


                              MsgBox "The CD-ROM Drive: " & _ 


                              Drive.DriveLetter 


                              End If 


                              Next 


                              End Sub 


    FileSystem                文件系统,例如,FAT, NTFS或CDFS 


    IsReady                   如果合适的媒体(例如CD)插入了并且可以访问则返回True 






                              Function IsCDROMReady(strDriveLetter) 






                              Dim fs, objDrive 






                              Set fs = CreateObject("Scripting.FileSystemObject") 






                              Set objDrive = fs.GetDrive(strDriveLetter) 


                              IsCDROMReady = (objDrive.DriveType = 4) And _ 






                              objDrive.IsReady = True 


                              ' run this function from the Immediate window 






                              ' by entering: ?IsCDROMReady("D:") 


                              End Function 


    Path                      根文件夹路径 


    SerialNumber              驱动器系列号 


    TotalSize                 驱动器总容量,以字节表示 






29.使用 WSH 创建文本文件 






WSH提供了三种创建文本文件的方法:CreateTextFile,OpenTextFile和OpenAsTextStream。下面 


的表格里列出了每种方法和示例。 






    方法/语法                     示例 


    CreateTextFile            object.CreateTextFile(filename[, overwrite[, unicode]]) 


                              Object是对象FileSystemObject或Folder的名称。 


                              filename是明确要创建文件的字符串表达式。 


                              Overwrite (可选的) 是个布尔值,表明你是否要覆盖已经存在 


                              的文件,如果可以覆盖那么该值为True,如果不能覆盖则为 


                                        162 




----------------------- Page 180-----------------------


                         False,如果忽略,那么现存的文件将不会被覆盖。 


                         Unicode (可选的) 是个布尔值,表明该文件创建为Unicode或者 


                         ASCII类型的文件。如果文件创建为Unicode类型那么该值为真, 


                         如果文件为ASCII的话那么该值为假。如果忽略掉,那么就会创 


                         建ASCII类型的文件。 


                         Sub CreateFile_Method1() 


                         Dim fs, objFile 


                         Set fs = CreateObject("Scripting.FileSystemObject") 






                         Set objFile = fs.CreateTextFile("C:\Phones.txt", True) 






                         objFile.WriteLine ("Margaret Kubiak: 212-338-8778") 


                         objFile.WriteBlankLines (2) 






                         objFile.WriteLine ("Robert Prochot: 202-988-2331") 


                         objFile.Close 


                         End Sub 


                         上面的过程创建了一个文本文件来储存两个人的姓名和电话号 


                         码 。 因 为 在 覆 盖 参 数 处 是 一 个 True 布 尔 值 , 所 以 


                          , 如 果 


OpenTextFile             C:\Phones.txt已经存在的话就会被覆盖。 


                         object.OpenTextFile(filename[,  iomode[,      create[, 


                         format]]]) 


                         Object是FileSystemObject对象的名称。 


                         Filename是明确要打开的文件名称的字符串表达式。 


                         Iomode (可选的) 是个布尔值,表示如果该文件不存在时是否创 


                         建一个新文件,如果可以创建新文件则为真,否则为假。如果忽 


                         略该参数,那么不会创建新文件。(译者,红色段落为原文翻译, 


                         应该是错误的) 


                         参数iomode 可以是下述常数之一: 


                         ForReading (1) 


                         ForWriting (2) 


                         ForAppending (8) 


                         Create (可选的) 是个布尔值,表示如果该文件不存在时是否创 


                         建一个新文件,如果可以创建新文件则为真,否则为假。如果忽 


                         略该参数,那么不会创建新文件。 


                         Format (可选的) 是用来表明打开文件类型的三种类型之一。如 


                         果忽略,文件就会打开为ASCII。 


                         TristateTrue = 打开文件为ASCII. 


                         TristateFalse =打开文件为Unicode. 


                         TristateUseDefault = 使用系统默认方式打开文件 


                         Sub CreateFile_Method2() 


                         Dim fs, objFile 


                         Set fs = CreateObject("Scripting.FileSystemObject") 






                         Set objFile = fs.OpenTextFile("C:\Shopping.txt",_ 


                         ForWriting, True) 


                         objFile.WriteLine ("Bread") 


                         objFile.WriteLine ("Milk") 


                         objFile.WriteLine ("Strawberries") 


                         objFile.Close 


OpenAsTextStream         End Sub 






                         object.OpenAsTextStream([iomode, [format]]) 






                         Object是File对象名称。 


                         Iomode (可选的) 表明读写模式,它可以是下述三个常数之一: 






                                   163 




----------------------- Page 181-----------------------


                              ForReading (1) 


                              ForWriting (2) 


                              ForAppending (8) 


                              Format (可选的) 是用来表明打开文件类型的三种类型之一。如 


                              果忽略,文件就会打开为ASCII。 


                              TristateTrue = 打开文件为ASCII. 


                              TristateFalse =打开文件为Unicode. 


                              TristateUseDefault = 使用系统默认方式打开文件 


                              Sub CreateFile_Method3() 


                              Dim fs, objFile, objText 






                              Set fs = CreateObject("Scripting.FileSystemObject") 


                              fs.CreateTextFile "New.txt" 






                              Set objFile = fs.GetFile("New.txt") 


                              Set objText = objFile.OpenAsTextStream(ForWriting, _ 






                              TristateUseDefault) 


                              objText.Write "Wedding Invitation" 


                              objText.Close 






                              Set objText = objFile.OpenAsTextStream(ForReading, _ 


                              TristateUseDefault) 


                              MsgBox objText.ReadLine 


                              objText.Close 


                              End Sub 






30.使用 WSH 进行其它操作 






WSH使任何安装在你计算机上的自动化对象的操作成为可能。 


除通过FileSystemObject访问文件系统之外,WSH也允许你进行其它的一些操作,例如,处理WSH 


和ActiveX对象,设定和去除打印机和远程驱动器,操纵注册表,创建视窗和互联网快捷方式以及 


访问Windows NT 活动地址服务。WSH对象模型由下述三种主要对象组成:WScript,WshShell和 


WshNetwork。本节示范如何利用WshShell对象来编写程序启动其它应用程序和创建快捷方式。 






31.运行其它应用程序 






在本书的下一章,你将学习多种从Excel里启动外部应用程序的方法。你可以加上即将在本节找到 


的三种方法。 


假设你想要从VBA过程里启动Windows记事本,接下来的过程,你将看到使用WSH的对象WshShell来 


运行一个应用程序是多么容易。如果你要运行内置的计算器的话,只要将记事本应用程序名称改为 


Calc就可以了。 


Sub RunNotepad() 


     Dim WshShell As Object 






     Set WshShell = CreateObject("WScript.Shell") 


     WshShell.Run "Notepad" 


     Set WshShell = Nothing 


End Sub 


上面的过程以声明和创建一个Wshshell对象开始: 


Dim WshShell As Object 


Set WshShell = CreateObject("WScript.Shell") 






下一语句则使用Run方法来运行要求的应用程序: 


WshShell.Run "Notepad" 


使用相同的概念,很容易运行视窗的公用应用程序,例如计算器或浏览器: 






                                        164 




----------------------- Page 182-----------------------


WshShell.Run “Calc” 


WshShell.Run “Explorer” 


过程的最后一行消灭了对象WshShell,因为,不再需要它了。 


Set WshShell = Nothing 


你可以启动你应用程序和某个特定的文件,而不是打开一个空的应用程序窗口,如下所示: 


Sub OpenTxtFileInNotepad() 


     Dim WshShell As Object 






     Set WshShell = CreateObject("WScript.Shell") 


     WshShell.Run "Notepad C:\Phones.txt" 






     Set WshShell = Nothing 


End Sub 


试验下面的过程来打开MS-DOS窗口,并且将当前目录下的文件清单打印出来: 


Sub RunDOSCommand() 


     Dim WshShell As Object 






     Set WshShell = CreateObject("WScript.Shell") 


     WshShell.Run ("Command /c Dir >lpt1:") 






End Sub 






32.创建快捷方式 






当你开始传播你的VBA应用程序的时候,用户可能会要求你自动在他们的桌面上放置一个你的软件 


的快捷方式。VBA自己没有提供创建快捷方式的方法。很幸运的是,你现在知道如何使用WSH了,你 


可以使用它的对象Shell创建应用程序或者网页的快捷方式,不必要用户的干涉。对象WshShell使 


用了方法CreateShortcut,你可以按照下述方法: 


Set myShortcut = WshShell.CreateShortcut(Pathname) 






Pathname是明确快捷文件完整路径的字符串。所有的快捷方式文件都有扩展名.lnk,并且该扩展名 


必须包括在文件路径名里面。CreateShortcut方法返回快捷方式对象,下面的表格里列出了很多属 


性和一个方法。 






    方法/语法                    示例 


    TargetPath               TargetPath属性是可执行文件的路径 






                             WshShell.TargetPath = ActiveWorkbook.FullName 


    WindowStyle              WindowStyle属性明确快捷方式使用的窗口类型 


                             1 – 普通窗口 


                             3 – 最大化窗口 


                             7 – 最小化窗口 


                             WshShell.WindowStyle = 1 


    HotKey                   HotKey 属 性 是 键 盘 快 捷 方 式 ( 例 如 , Alt+f, Shift+g, 


                             Ctrl+Shift+z, 等等) 


                             WshShell.Hotkey = "Ctrl+Alt+w" 


    IconLocation             IconLocation属性是快捷方式图标的位置。因为图标文件里通常 


                             不止一个图标,所以你应该提供图标文件的路径,并且后面标明 


                             图标在文件里的索引号。如果不明确的话,Windows 会使用缺省 


                             的图标。 






                             WshShell.IconLocation = "notepad.exe, 0" 


    Description              Description属性包含一个描述快捷方式的字符串 






                             WshShell.Description = "Wordware Web Site" 


    WorkingDirectory         WorkingDirectory属性明确快捷方式的工作目录 






                             strWorkDir = WshShell.SpecialFolders("Desktop") 


                             WshShell.WorkingDirectory = strWorkDir 


    Save                     这是对象Shortcut的唯一方法。在使用方法CreateShortcut创建 






                                       165 




----------------------- Page 183-----------------------


                             一个快捷方式对象并且设置该快捷方式的属性后,必须使用Save 


                             方法将快捷方式对象保存到硬盘上。 






创建快捷方式是个三步的过程: 


1. 创建一个WshShortcut对象 


2. 初始化它的属性 


3. 用方法Save将它保存到硬盘 


下面的例子创建一个WshShell对象和使用CreateShortcut方法创建两个快捷方式:一个到当前 


Excel工作簿的Windows快捷方式,和一个到Wordware Publishing网页的互联网快捷方式。两个快 


捷方式都放在用户的桌面上。该过程使用对象WshShell的SpecialFolders属性来返回到视窗桌面的 


路径。 


Sub CreateShortcut() 


     ' this script creates two desktop shortcuts 


     Dim WshShell As Object 


     Dim objShortcut As Object 


     Set WshShell = CreateObject("WScript.Shell") 






     ' create an internet shortcut 


     Set objShortcut = WshShell.CreateShortcut(WshShell. _ 






          SpecialFolders("Desktop") & "\Wordware.url") 


     objShortcut.TargetPath = "http://www.wordware.com" 


     objShortcut.Save 


     ' create a file shortcut 


     Set objShortcut = WshShell.CreateShortcut(WshShell. _ 






          SpecialFolders("Desktop") & "\" & ActiveWorkbook.Name & ".lnk") 


     With objShortcut 


          .TargetPath = ActiveWorkbook.FullName 






          .WindowStyle = 7 


          .Save 


     End With 


     Set objShortcut = Nothing 


     Set WshShell = Nothing 


End Sub 


技巧8-12 使用SpecialFolders属性 


你可以使用SpecialFolders属性在你的机器上找到特殊文件夹的位置。下述特殊文件夹是可用的: 


AllUsersDesktop(所有用户桌面), AllUsersStartMenu(所有用户开始菜单),AllUsersPrograms 


(所有用户程序),AllUsersStartup(所有用户启动),Desktop(桌面),Favorites(收藏),Fonts 


(字体),MyDocuments(我的文档),NetHood(网络连接),PrintHood(打印机),Programs(程 


序),Recent(最近),SendTo(发送到),StartMenu(开始菜单),Startup(启动)和 Templates 


(模版)。如果请求的特殊文件夹不可用,那么SpecialFolders属性就会返回一个空字符串。 






33.接下来…… 






在本章的课程里,你学习并且测试了让你操作文件系统的VBA函数和语句。你知道了如何读取和修 


改与文件和文件夹有关的信息,而且,知道了如何执行对顺序,随机和二进制文件的读和写的操作。 


你也学习了如何使用WSH来访问FileSystemObject和进行其它操作,例如启动应用程序和使用对象 


WshShell创建Windows快捷方式。如果你对讨论的函数和语句更详细的东西感兴趣的话,那么就花 


些时间来浏览一下VB在线帮助吧。 


接下来的一章将给你介绍更多的自动化任务。例如,你将学习如何使用VBA来控制其它应用程序。 


你将学习启动应用程序的多种方法,并且研究如何直接从Microsoft Excel里操纵其它应用程序。 






                                       166 




----------------------- Page 184-----------------------


                       第九章 利用 VBA 控制其它应用程序 






你每天在办公室里或者家里在你的电脑上工作时,都要用到很多种应用程序。要从你的硬盘或者软 






盘上查找某个文件的话,你就要打开视窗浏览器。当你要设置系统时间或者更改屏幕外观的话,可 


以点击控制面板上的相应的图标。如果你的电脑上安装了微软办公软件套餐的话,就可以使用Word 


创建各种各样的文件,并且依靠Excel进行所有的计算。微软Access对于保存重要的数据表非常有 


用,而PowerPoint则有助于你使用声音和图片。最后,微软Outlook使你易于保存你的联系、时间 


和约会并且分享给他人。使用这些应用软件的时候,你经常要在他们之间切换,你可以使用键盘直 


接输入数据或者复制或移动数据。这些操作——打开应用程序以及在它们之间传输数据时不需要手 


动操作的。它们可以通过一些很有趣的VBA函数和指令来自动完成。在本章,你将学习多种从VBA 


过程里打开应用程序的方法,并且找到如何使用称为自动化的技术直接从微软Excel直接控制其它 


应用程序。 






1.启动应用程序 






启动一个应用程序的方法不止一个,实际上,你至少可以使用五种方法手动打开某个程序:通过“开 


始”|“程序”菜单,快捷键,“运行”命令,MS-DOS窗口,或者在视窗浏览器里双击可执行文件。 


本节假设你对手动启动应用程序很熟悉,并且很想从Excel内部的VB编辑窗口试验其它启动应用程 


序的方法。 


我们从最简单的开始吧——Shell函数。该函数使你可以从VBA过程里直接打开任意程序。假设你的 


过程必须打开视窗记事本,要打开记事本,你所有要做的就是在关键字Sub和End Sub之间加上一条 


语句,或者更好的方法是在立即窗口里输入下述语句,并且按下回车键: 


Shell "notepad.exe", vbMaximizedFocus 


你将立即看到结果。 


在上面的语句里,“notepad.exe”是你要打开的程序的名称。如果你担心程序找不到的话,那么该 


名称就应该包含完整的路径(启动器名称和文件夹名称)。注意,程序名称用双引号括起来了。Shell 


函数的第二个参数可以忽略。该参数明确窗口形式(也就是当程序启动的时候,它如何显示在屏幕 


上的)。在上面的例子里,记事本将显示为最大化的窗口。如果没有明确窗口形式,那么程序就会 


被最小化(参见表9-1)。 


窗口形式常数                 值           窗口显示情况 


vbHide                 0           窗口被隐藏 


vbNormalFocus          1           普通大小,并带焦点 


vbMinimizedFocus ( 默 认 2           最小化,并带焦点(这是缺省设置) 


设 


置)                     3           最大化,并带焦点 


vbMaximizedFocus       4           普通大小,并失去焦点 


vbNormalNoFocus        6           最小化,并失去焦点 


vbMinimizedNoFocus 






如果Shell函数能够启动某个可执行文件,那么它就会返回一个叫做任务ID的号码。该号码是指示 


应用程序启动的唯一号码。如果Shell函数不成功的话(也就是说某应用程序不能打开),VB就会产 


生一错误。如果你要使用Shell函数启动的应用程序的话,就不要在Shell函数后面输入任何语句。 


Shell函数启动程序是不同时的,意思是说VB启动Shell函数指定的应用程序,并且,VB在启动程序 


后,立即就回到过程里面去继续剩余的指令(因此,你没有机会立即使用该应用程序)。你如果使 


用Shell函数来启动控制面板呢? 


1. 打开一新工作簿,保存为Chap09.xls 


2. 在VB编辑器窗口,插入新模块 


3. 重新命名工程为WorkWApplets,模块名为ShellFunction 


4. 输入下面显示的过程StartPanel: 


Sub StartPanel() 


     Shell "Control.exe", vbNormalFocus 


End Sub 


控制面板里面有很多图标,每个图标执行一个或者多个任务。众所周知,在每个图标后面都有一个 






                                  167 




----------------------- Page 185-----------------------


程序的,当用户双击图标或者用箭头选择该图标然后按下Enter键,该程序都会被激活。作为一个 


规律,你总是可以通过查看某个图标的属相来检查什么文件名驱动某个图标。不幸的是,控制面板 


里面的图标的属性选择都被禁止了。然后,你可以通过创建一个到该图标的快捷键来查找控制面板 


里图标文件。例如,在你创建一个更改电脑原始设置的过程之前,我们来找出激活该图标的文件名 


称。 


1. 从“开始”菜单里选择“设置”,然后选择“控制面板”(在Windows XP开始菜单里可以直接看 


   到“控制面板”) 


2. 在控制面板窗口里,右键单击“初始选项”图标,并且从快捷菜单中选择创建快捷键 


3. 点击确定,将快捷键放在桌面上 


4. 关闭控制面板窗口 


5. 返回桌面,在初始选项的快捷键上单击右键,然后选择属性 


6. 在属性窗口,点击快捷键页,然后点击更改图标按钮 






图9-1 每个控制面板里的图标都有一个后缀名为.cpl的文件 


7. 写下.cpl文件名称(Control Panel Library)或者动态链接库文件(.dll)并关闭该练习中开 


   启的所有窗口 


表9-2 激活控制面板图标的一些文件示例 


控制面板图标                   .cpl或者.dll文件 


电话和调制解调器选项               TELEPHON.CPL或MODEM.CPL 


添加/删除程序                  APPWIZ.CPL 


网络和拨号连接                  NETCPL.CPL或NETSHELL.DLL 


32-Bit ODBC              ODBCCP32.CPL 


系统                       SYSDM.CPL 


邮件                       MLCFG32.CPL 


用户和密码                    PASSWORD.CPL或NETPLWIZ.DLL 


日期/时间                    TIMEDATE.CPL 


区域选项                     INTL.CPL 


Internet选项               INETCPL.CPL 


声音和多媒体属性                 MMSYS.CPL 


显示                       DESK.CPL 


鼠标                       MAIN.CPL 






下面的国产ChangeSettings示范如何使用Shell函数来启动控制面板的初始设置图标。注意Shell 


函数的参数必须写在括号里,如果你后面需要在你的程序里使用它返回值的话。 


1. 在当前模块里输入过程ChangeSettings,如下所示: 


Sub ChangeSettings() 


     Dim nrTask 


     nrTask = Shell("Control.exe intl.cpl", vbMinimizedFocus) 






     Debug.Print nrTask 


End Sub 


2. 运行几次过程ChangeSettings,每次从表9-2里列出的清单里提供一个不同的.cpl文件。你可能 






                                   168 




----------------------- Page 186-----------------------


   需要将程序改为: 


Sub ChangeSettings2() 


     Dim nrTask 


     Dim iconFile As String 






     iconFile = InputBox("Enter the name of the CPL or DLL file:") 


     nrTask = Shell("Control.exe " & iconFile, vbMinimizedFocus) 


     Debug.Print nrTask 


End Sub 


如果你要启动的程序是微软应用程序,那么除了使用Shell函数外,你还可以很方便地使用VB的方 


法ActivateMicrosoftApp来实现。该方法在微软Excel应用程序的对象里是可用的,例如,要从立 


即窗口启动PowerPoint的话,你所有要做的事情就是输入下面的指令并且按下Enter: 






Application.ActivateMicrosoftApp xlMicrosoftPowerPoint 


注意ActivateMicrosoftApp方法要求一个常量来指定要启动的程序。如果PowerPoint没有打开的 


话,上面的过程就会打开PowerPoint,但是如果该程序已经打开的话,该指令不会再打开一个新的 


PowerPoint界面,只是简单的激活已经在运行的应用程序。你可以结合ActivateMicrosoftApp方法 


使用下列常量,常量的名称指名应用程序名称。 


应用程序名称                   常量 


Access                   xlMicrosoftAccess 


FoxPro                   xlMicrosoftFoxPro 


Mail                     xlMicrosoftMail 


PowerPoint               xlMicrosoftPowerPoint 


Project                  xlMicrosoftProject 


Schedule                 xlMicrosoftSchedulePlus 


Word                     xlMicrosoftWord 






2.在应用程序之间切换 






因为用户可以同时在Windows环境下使用多个应用程序,所以你的VBA过程必须要知道如何在打开的 


程序之间切换。假设除了Excel之外,你还打开了另外两种应用程序:Word和Explorer。你可以按 


照下面的语法使用AppActivate语句来激活已经打开的程序: 


AppActivate title [, wait] 


只有标题参数是必须的,这是应用程序的名称,正如它显示在应用程序窗口的标题栏那样,或者它 


也可以是Shell函数返回的任务ID号码。注意,参数title要跟每个正运行的应用程序的标题字符串 


进行对比,如果没有精确的匹配,那么任何标题字符串里前面的字符和参数title一致的应用程序 


就会被激活。(译者:例如,你要激活Excel,那么title参数应该是“Microsoft Excel”,如果你 


写的是“Microsoft”,那么激活的就也可能是Word,PowerPoint……)。第二个参数wait是可选的, 


它是个布尔值(True或False),明确VB什么时候激活应用程序。如果在这里是False的话,该应用 


程序就立即会被激活,甚至被调应用程序并没有焦点。如果在wait参数处放置True的话,那么被调 


的应用程序就会等到它有了焦点,然后才会激活该应用程序。例如,要激活Word,你就得输入下列 


语句: 


AppActivate “Microsoft Word” 


注意,应用程序名称用双引号引用起来。你也可以使用Shell函数返回的数值作为语句AppActivate 


的参数: 


‘ run Microsoft Word 运行Word应用程序 


ReturnValue = Shell("C:\Microsoft Office\Office\Word.exe",1) 


‘ activate Microsoft Word 激活Word 


AppActivate ReturnValue 


语句AppActivate用来在应用程序之间切换,所以要求这些程序已经在运行。该语句仅仅改变焦点, 


指定的应用程序变为当前活动的窗口。AppActivate语句不会启动任何应用程序,参见下一章节的 


过程FindCPLFiles,这也是使用该语句的一个例子。我们来练习一下最近介绍的几个VBA语句: 






                                    169 




----------------------- Page 187-----------------------


1. 通过在立即窗口里输入下列VBA语句来打开资源管理器: 


Shell "Explorer" 


按下回车键后,被请求的应用程序就被打开了,带有“我的文档”文件夹的图标就会出现在任务栏 


上。 


2. 在立即窗口里输入下列代码: 


AppActivate "My Documents" 


按下回车键后,焦点就会移至我的文档窗口。 






3.控制其它应用程序 






既然你已经知道了如何使用VBA语句来启动一个程序,以及在应用程序之间切换,那么我们来看看 






一个应用程序是如何与另外一个应用程序交流的。对于一个应用程序来说,要控制另一个应用程序 


的最简单的方式就是使用SendKeys语句。该语句允许你将许多的按键发送到活动应用程序窗口,你 


可以发送一个或组合键并且得到直接使用键盘的同样效果。SendKeys语句如下所示: 


SendKeys string [, wait] 


这个必须的参数string是你要发送到活动应用程序窗口的键或组合键,例如,使用下列指令来发送 


字母“f”键: 


SendKeys "f" 


要发送组合键Alt+f,使用: 


SendKeys "%f" 


百分符号(%)是表示Alt键的字符串。要发送例如Shift+Tab的组合键的话,那么就要使用下面的 


语句: 


SendKeys "+{TAB}" 






加号(+)表示Shift键。要发送其它键或者其它组合键的话,请参见表9-3列出的相应字符串。 


技巧9-1 SendKeys和其它应用程序 


你只能发送按键到那些为微软视窗操作系统设置的应用程序。 


技巧9-2 SendKeys和被保护的字符 


有些字符在和SendKeys语句一起使用时具有特殊的意义,它们是:加号(+),脱字符号(^),符合 


(~)和括号()。要发送这些字符到另一个应用程序的话,就必须将它们用打括号{}括起来。要发 


送打括号时,则需要输入{{}和{}} 


SendKeys语句的第二个参数是可选的,wait是个逻辑值True或者False。如果是False(缺省),那 


么VB在发送按键后立即返回过程,如果为True,那么VB只有在发送的按键执行后才能返回到过程。 


如果要发送一个表格9-3里面没有列出的字符的话,那么记住这些代码必须用引号括起来,例如: 


SendKeys “{BACKSPACE}” 


表9-3 SendKeys语句里使用的按键代码 


键                代码                 键                  代码 


空格键              {BACKSPACE}        滚动锁定               {SCROLLLOCK} 


                 {BS}               Tab                {TAB} 


                 {BKSP}             向上箭头               {UP} 


Break键           {BREAK}            F1 


大写锁定键            {CAPSLOCK}         F2                 {F2} 


删除键              {DELETE}           F3                 {F3} 


                 {DEL}              F4                 {F4} 


向下箭头             {DOWN}             F5                 {F5} 


End键             {END}              F6                 {F6} 


回车键              {ENTER}            F7                 {F7} 


                 ~                  F8                 {F8} 


Esc键             {ESC}              F9                 {F9} 


帮助键              {HELP}             F10                {F10} 


Home键            {HOME}             F11                {F11} 


插入键              {INSERT}           F12                {F12} 






                                    170 




----------------------- Page 188-----------------------


                  {INS}               F13                 {F13} 


向左箭头              {LEFT}              F14                 {F14} 


数字锁定键             {NUMLOCK}           F15                 {F15} 


向下翻页键             {PGDN}              F16                 {F16} 


向上翻页键             {PGUP}              Shift               + 


屏幕打印键             {PRTSC}             Ctrl                ^ 


向右箭头              {RIGHT}             Alt                 % 






技巧9-3 SendKeys语句对格敏感 


当你使用SendKeys语句发送按键时,你一定要牢记区分字符的大小格。因此,要发送组合键Ctrl+d 


的话,你必须使用^d,而发送Ctrl+Shift+D的话,则必须使用字符串:^+d 


在本章前期,你学习了.cpl文件启动多种控制面板的图标。你现在要创建的VBA过程目的是要定位 


你硬盘上所有扩展名为.cpl的文件。 


1. 使用立即窗口来启动资源管理器: 


Shell “Explorer.” 


“我的文档”图标将出现在屏幕下方的任务栏上。 


2. 在当前工程里插入新模块并且重命名为SendKeysStatement 


3. 输入过程FindCPLFiles,如下所示: 


Sub FindCPLFiles() 


     ' The keystrokes are for Windows 2000 






     AppActivate "My Documents" 


     ' activate the Search window 激活搜索窗口 






     SendKeys "{F3}", True 


     ' move the pointer to the Search for files将光标移到搜索文件 


     ' and folders named text box 和文件夹(名称在文本框里) 


     SendKeys "%m", True 


     ' type in the search string 输入要搜索的字符串 


     SendKeys "*.cpl", True 


     ' move to the Look in drop down box 焦点移到下拉框 


     SendKeys "{Tab}{Tab}", True 






     ' change to the root directory 更改根目录 


     SendKeys "C:\", True 


     ' execute the Search 执行搜索 


     SendKeys "%s", True 


End Sub 


4. 切换到Excel应用程序窗口并且运行过程FindCPLFiles(使用Alt+F8打开宏对话框,选择过程名 


   称,再点击运行)。 


上面过程的第一条语句使用AppActivate语句(参见前面章节)来激活已经打开的应用程序,还记 


得你在立即窗口里使用Shell语句激活了资源管理器吗?剩余的语句发送一些必要的按键到活动应 


用程序。本过程的结果是扩展名为.cpl的控制面板文件的搜索结果列表。你也可以使用一个 


SendKeys语句来发送所有必须的按键(参见下面的例子),然而,一步一步发送按键更容易理解程 


序。 


Sub FindCPLFiles2() 


     AppActivate "My Documents" 






     SendKeys "{F3}% m*.cpl{Tab}{Tab}C:\%s", True 


End Sub 






4.控制应用程序的其它方法 






尽管你可以使用SendKeys语句来传递命令给其它应用程序,但是你还是必须要求助于其它方法来获 


得对该应用程序的充分控制。有两种标准方法可以供应用程序和另外一种应用程序交流。最新的方 






                                       171 




----------------------- Page 189-----------------------


法,被称为自动控制,它允许你访问和操纵另一种应用程序的对象。你可以通过自动控制编写VBA 


过程,通过引用其它应用程序的对象、属性和方法来控制其它应用程序。在本章接下来的章节里, 


你将学习如何通过自动控制来控制其它应用程序。称为DDE(动态数据交换)的老数据交换技术是 


允许你在两个应用程序之间动态发送数据的协议,它通过创建一个特殊的通道来发送和结束信息。 


DDE非常慢,使用困难,只有当你需要与一个不支持自动控制的老应用程序交流时,才需要使用DDE。 






5.了解自动控制 






当和另外一个应用程序交流时,你可能需要更多的功能,而不只是激活它来发送按键。例如,你可 


能需要在该应用程序里创建和操纵对象,你可以在Excel电子表格力插入整个Word文档。因为Excel 


和Word都支持自动控制,所以,你可以在Excel里编写一个VBA过程在操作Word对象,比如文档或者 


段落。支持自动控制的应用程序称为自动控制服务器(Automation servers)或者自动控制对象 


(Automation objects)。 


能够操作服务器对象的应用程序称为自动控制控件。有些应用程序只能是服务器或者控件,而其它 


的则既可以是服务器也可以是控件。Microsoft Office 2000和2002都可以作为自动控制服务器和 


控件。自动控制控件可以是安装在你电脑上的各种ActiveX控件,你将在下一章里学习这些对象。 






6.了解链接和嵌入 






在你学习如何使用自动控制从VBA过程控制其它应用程序之前,我们来看一看如何手动链接和插入 


对象。人们熟知的OLE,对象链接和嵌入,允许你创建组合文档。组合文档包含其它应用程序创建 


的对象。例如,如果你要在Excel里嵌入一个Word文档的话,Excel只要知道创建该对象需要用到的 


应用程序名称,以及该对象在屏幕上显示的方法。组合文档有链接或者对象嵌入产生。当你使用手 


动方法来嵌入对象时,你首先要在一个应用程序里复制它,再粘贴到另一个应用程序里。链接对象 


和嵌入对象的主要区别是对象储存和更新的方式。我们来试验一下: 


1. 激活Word并打开任意一个文档 


2. 选择和复制任意一段文本 


3. 在Excel工作表里,使用下述四种方法之一将复制的文本进行粘贴: 


   •     粘贴为文本(选择编辑|粘贴)。复制的文本就会出现在活动单元格(见图9-2,单元格 


       A2) 


   •     粘贴为嵌入对象(选择编辑|选择性粘贴,点击“粘贴选项”按钮,并且在清单里选择 


       “Microsoft Word Document 对象”。)粘贴的文本将作为一个嵌入的对象(见图9-2,单 


       元格A5)。该嵌入的对象成为了目的文件的一部分。因为该嵌入的对象没有和原始数据链 


       接,所以该信息是静态的。当文件源中的数据改变时,该嵌入的对象不会被更新。如果要 


       更改嵌入的数据,你就必须双击它,这样就会打开该对象在源程序里编辑它。当然,该源 


       程序必须已经安装在你的电脑上了。当你嵌入对象时,所有的数据都会存储在目的文件里, 


       这会导致文件大小显著增大。注意,当你嵌入一个对象后,Excel的编辑栏里将显示: 


       =EMBED("Word.Document.8","") 


   •     粘贴为链接对象(选择编辑|选择性粘贴,点击“粘贴链接”选项,然后在列表里选择 


       “Microsoft Word Document 对象”)。虽然目的文件显示了所有的数据,但是它仅仅储存 


       了该数据的地址。当你双击该链接的对象时(见图9-2,单元格A9),原应用程序就会被启 


       动。链接对象是一种动态的操作,这意味着当源文件里的数据改变时,链接的数据就会自 


       动更新。因为目的文件只包含对象如何与源文件链接的信息,所以,对象链接并不会增加 


       目的文件的大小。下面的公式是Excel用来链接对象的: 


       =Word.Document.8|'C:\Documents      and           Settings\tj8147\My 


       Documents\Tiger\VB\Excel2002_Programming\Chinese\Excel2002VBA_Ch9.doc'!'!OLE_ 






       LINK2'(译者:由于文件存储位置不同,本节的翻译可能和你的情况不一样,请注意分辨) 


   •     粘贴为超链接(选择粘贴|超链接译者:应该为“编辑”|“粘贴为超链接”)粘贴的数 


       据在工作表里显示为带下划线、有颜色的文本(见图9-2,单元格A11)。点击该超链接, 


       你可以快速地激活该源文件。 






                                   172 




----------------------- Page 190-----------------------


图9-2 示范链接和嵌入 






7.使用 VBA 进行链接和嵌入 






过程InsertLetter示范了如何使用程序在Excel嵌入一个Word文档。用你自己的文件名称代替引用 






“C:\Hello.doc”。过程InsertLetter使用AddOLEObject方法,该方法创建一个OLE对象,并且返回 


一个对表该新OLE对象的Shape对象。在VB在线帮助里面,你可以找到AddOLEObject方法可用的其它 


参数。 


1. 在当前工程里面插入一新模块,并重命名为OLE 


2. 输入过程InsertLetter,如下所示: 


Sub InsertLetter() 


     Workbooks.Add 






     ActiveSheet.Shapes.AddOLEObject FileName:="C:\Hello.doc" 


End Sub 


上面的过程打开一个新工作簿,然后嵌入该指定的Word文档。要链接一个文档的话,你就必须明确 


另外一个参数Link,如下所示: 


ActiveSheet.Shapes.AddOLEObject _ 






FileName:="C:\Hello.doc", Link:=True 


技巧9-4 对象链接和嵌入 


当你不得不做出决定是否使用嵌入还是链接对象时,只要有下列之一的条件,那么就使用嵌入: 


•        你不在乎文档大小,或者你有足够的硬盘空间和内存来处理大文件 


•        你再也不会在其它复合文档里使用源文件或者源文本 


•        你想要将该文档通过电子邮件或者磁盘发送给别人,并且确保他们能够顺利地读取数 


     据。 


(译者:本人也倾向于使用嵌入,因为链接经常会问你是否要更新链接,而且,很多人经常会忘记 


发送源文件给别人。) 






                                   173 




----------------------- Page 191-----------------------


8.COM 和自动控制 






在自动控制后面的驱动力量是组件对象模型(COM),它决定了服务器应用程序创建对象的规则,也 






明确服务器和控制应用程序在使用这些对象时必须遵循的方法。COM标准包含作为自动控制界面 


(Automation interfaces)可用的函数集合。 


当服务器应用程序创建一个对象是,它会自动地制作一个和它一起可用的界面。该界面包括该对象 


可识别的属性、方法和事件。控制应用程序不需要为了控制该对象去了解它的内部结构,只需要知 


道如何操作服务器应用程序制作的对象界面。 






9.了解绑定 






对于控制应用程序与自动控制对象(服务器)来说,你必须将你的VBA过程中可用的对象和服务器 






实际的自动控制对象联系起来,这个过程就叫做绑定。这里有两种类型的绑定:后期绑定和早期绑 


定。你对绑定的选择对你的应用程序表现影响很大。 






10.后期绑定 






当你声明一个变量 As Object 或者As Vaiant时,VB使用的是后期绑定。后期绑定也叫运行绑定。 


简单地说,后期绑定意味着VB在设计时不会将你的对象变量和自动控制对象联系起来,而是要等到 


你实际运行该过程时才联系起来。因为As Object或者As Variant的声明在本质上是非常普通的, 


所以,VB在汇编时不能决定你变量指向的对象真正具有你的VBA过程使用的属性和方法。 


下面的声明导致对指定对象的后期绑定: 


Dim mydoc As Object 


后期绑定的优势是所有的自动控制对象都知道如何使用。 


后期绑定的劣势是对内置常量不支持。因为在设计时,VB并不知道你的对象指向的类型库,所以, 


你必须通过在应用程序文档里查询数值在你的代码里定义常量。同样,在运行时询问应用程序将放 


慢你程序的执行。 


注意:后期绑定使得在另外一个应用程序的类型库里访问对象称为可能,而不需要首先建立对该对 


象库的引用。如果你不肯定你的用户是否在他们的机子上安装了要指向的类型库,那么就使用后期 


绑定。 


下面的过程示范如何使用后期绑定来打印Word文档。 


Sub PrintWordDoc() 


     Dim objWord As Object 






     Set objWord = CreateObject("Word.Application") 


     With objWord 


         .Visible = True 


         .Documents.Open "C:\Hello.doc" 


         .Options.PrintBackground = False 


         .ActiveDocument.PrintOut 


     End With 


     objWord.Documents.Close 


     objWord.Quit 


     Set objWord = Nothing 


End Sub 


技巧9-5 这是什么类型的绑定? 


无论何时你使用常用的Object或Variant数据类型声明对象变量,请考虑后期绑定。后期绑定和早 


期绑定的主要区别是你如何声明你对象变量。 






11.早期绑定 






当你声明对象变量为明确的对象类型时,VB使用的是早期绑定。早期绑定也熟知为汇编绑定。这意 


味着VB在源代码转变为可执行代码时期,就将你的对象变量和自动控制对象联系起来了。常见的语 


法如下所示: 


Dim objectVariable As Application.ObjectType 






                                   174 




----------------------- Page 192-----------------------


在上面的语法中,Application是应用程序的名称,正如它出现在对象浏览器里的工程库下拉清单 


里的样子(例如Word和Excel)。ObjectType是对象类型(例如应用程序,文档,工作簿,工作表)。 


下面的声明导致早期绑定: 


Dim mydoc As Word.Document 


Dim mydoc As Excel.Worksheet 


早期绑定让你能够充分利用VB编辑器上可用的许多调试工具。例如你可以使用对象浏览器查找外部 


对象,属性和方法。VB的自动语法检测,自动列出成员以及自动显示快速信息(这些都在第二章里 


有讨论)可以让你在编写代码时更快,更少出错。另外,早期绑定允许你使用内置常量作为方法和 


属性设定的参数。因为这些常量在设计的时候在类型库里面就是可用的,所以你不需要定义它们。 


这些非常方便的内置语法检测,智能特点和对内置常量的支持,在后期绑定里是不可用的。虽然使 


用早期绑定的VBA过程执行得更快一些,但是一些非常老的视窗应用程序只能使用后期绑定。 


注意:为了使用早期绑定,你必须首先建立对对象库的引用(参见接下来的章节)。当你确定你的 


用户安装了引用的类型库时,就使用早期绑定。 






12.建立到对象库的引用 






如果你决定通过自动控制使用早期绑定连接到另外的应用程序的话,你首先就应该建立对包括你要 


操作对象的对象库的引用。依照下面的步骤创建对Microsoft Word 对象库的引用: 


1. 激活VB编辑器窗口 


2. 在工程浏览器里选择当前工程,并且选择“工具”|“引用” 


3. 在引用对话框里,选择“可使用的引用”列表框里面的应用程序名称。例如,点击Microsoft Word 


   9.0 Object Library或者 Microsoft Word 10.0 Object Library旁边的复选框(见图9-3)(译 


   者:这里引用的是Microsoft Word 11.0 Object Library)。拉下可用引用列表框的滚动条定位 


   该对象库,如果你已经安装了某个应用程序但是它的类型库在可用引用列表框里面没有出现的 


   话,那么你可以点击“浏览”按钮。 


4. 点击确定按钮关闭引用对话框。 


引用对话框列出了VBA工程可用的引用名称。没有使用的引用按字母顺序列出,勾选上了的引用按 


优先顺序列出。例如,在Excel里,Microsoft Excel 10.0 Object Library比Microsoft Word 10.0 


或者9.0 Object Library具有更高的优先顺序。当一个过程引用一个对象时,VB从引用对话框里列 


出的库里按顺序搜索所有被引用的对象库。 






图9-3 为了要操作其它应用程序的对象,你应该建立对该需要的对象库的引用 


在建立了对所要求对象库的引用后,你就可以在对象浏览器里浏览该对象的属性和方法。 






                                  175 




----------------------- Page 193-----------------------


图9-4 建立了对Microsoft Word 11.0 Object Library的引用后(见图9-3),Microsoft Word的所 


有对象,属性和方法都可以从Excel VBA工程里访问了。 






13.创建自动控制对象 






依照下列步骤,在你的VBA过程里创建一个自动控制对象: 


•  使用Dim…As Object或者Dim…As Application.ObjectType子句声明对象变量(参见前面章节 


   里的后期和早期绑定使用主题) 


•  如果你在使用早期绑定,那么使用引用对话框来建立对应用程序对象类型库的引用 


•  如果自动控制对象不存在,那么使用CreateObject函数;如果自动控制对象已经存在的话,那 


   么就使用GetObject函数来建立对该对象的引用 


•  使用关键字Set将CreateObject或者GetObject函数返回的对象赋值到对象变量 






14.使用 CreateObject 函数 






按照下面的语法,使用CreateObject函数从VBA过程里创建对自动控制对象的引用: 


CreateObject(class) 


参数class是你想要引用的应用程序的名称。该名称包含早先讨论的对象类类型(参见早期绑定部 


分)。必须使用关键字Set将自动控制对象赋予对象变量,如下所示: 


Set variable_name = CreateObject(class) 






例如,使用自动控制对象来激活Word,你的VBA过程里需要包括下面的声明语句: 


'early binding 早期绑定 


Dim wordAppl As Word.Document 






Set wordAppl = CreateObject("Word.Application") 


或者 


'late binding 后期绑定 


Dim wordAppl As Object 






Set wordAppl = CreateObject("Word.Application") 


通常,CreateObject函数创建该特定自动控制对象的新示例。然而,一些应用程序注册为一种叫做 


“单一示例”的应用程序了,这就是说你不能同时运行一个以上的示例。Microsoft Word和 


PowerPoint就是这种单一示例的应用程序,因此,如果Word或者PowerPoint已经在运行,那么 






                                   176 




----------------------- Page 194-----------------------


CreateObject函数就会直接引用到在运行的示例去,而不会再创建一个新的示例。 






15.使用自动控制创建一个新的 Word 文档 






我们来看看你如何将在前面章节学习到的关于绑定的知识应用到现实生活中的例子里。你也许有时 


需要从Excel直接通过程序打开一个Word文档,并且往里面写入数据,下面的例子使用了早期绑定。 


1. 在当前工程里插入新模块,并重命名为Automation 


2. 在工程浏览器里,选择当前工程,并且选择“工具”|“引用” 


3. 如果可用引用列表里的Microsoft Word 9.0 Object Library或者Microsoft Word 10.0 Object 


   Library没有被勾选,那么找到它们并勾选上,点击确定退出。 


4. 输入下面过程WriteLetter: 


   Sub WriteLetter() 


     Dim wordAppl As Word.Application 






     Application.StatusBar = "Creating Word Application Object..." 


     Set wordAppl = CreateObject("Word.Application") 


     With wordAppl 


          .Visible = True 


          Application.StatusBar = "Creating a new document..." 






          .Documents.Add 


          .ActiveDocument.Paragraphs(1).Range.InsertBefore "Invitation" 






          Application.StatusBar = "Saving document..." 


          .ActiveDocument.SaveAs "C:\Invite.doc" 


          Application.StatusBar = "Exiting Word..." 






          .Quit 


     End With 


     Set wordAppl = Nothing 


     Application.StatusBar = False 


   End Sub 


5. 切换到Excel应用程序窗口,并选择“工具”|“宏”|“宏”,找到过程WriteLetter并点击运行 


过程WriteLetter开始时声明对象变量为特定的对象类型(Word.Application)。回想这种生命(早 


期报道)要求你建立对Word对象库的引用(本章的前面讲过)。CreateObject函数返回的自动控制 


对象赋值到一个叫做wordAppl的对象变量,因为由子弟控制启动的应用程序不会出现在屏幕上,所 


以使用语句: 


wordAppl.Visible = True 


使启动的Word应用程序可见,这样你就可以观察VBA的工作情况。该过程里后面的语句打开一个新 


文档(Add方法),并且在第一段输入文本(InsertBefore方法),将文档保存到硬盘(SaveAs方法), 


以及关闭Word应用程序(Quit方法)。每条语句之前都有一条指令,将信息显示在Excel应用程序窗 


口下面的状态栏上。当Word应用程序关闭后,指令: 


Set wordAppl = Nothing 


清除对象变量,收回该对象占用的内存。语句: 


Application.StatusBar = False 


将状态栏上的信息恢复为默认的“就绪”。 


前面提到过,Word是单一示例(single-instance)应用程序,这意味着你不能同时运行一个以上 


的Word示例,简单说,如果你没有启动Word,WriteLetter过程里面的CreateObject函数将会启动 


Word,否则,它将会使用当前活动的Word示例。 






16.使用 GetObject 函数 






如果你确定自动控制对象以及存在并且已经打开,那么就考虑使用GetObject函数,如下所示: 


GetObject([pathname][, class]) 


GetObject函数有两个参数,它们都是可选的。使用第一个参数来明确你要打开的文件名称,应该 


提供完整的文件路径。如果你忽略该参数,那么不必须明确参数class,指明要使用的对象类型, 


例如: 


                                     177 




----------------------- Page 195-----------------------


Excel.Application 


Excel.Sheet 


Excel.Chart 


Excel.Range 


Word.Application 


Word.Document 


PowerPoint.Application 


在Invite.xls的基础上创建一个Excel对象,并且强制设置为Excel 5工作表,你可以使用下列声明: 


‘ late binding 后期绑定 


Dim excelObj As Object 


Set excelObj = GetObject("C:\Invite.xls", Excel.Sheet.5") 






要设定对象变量为某个特定的Word文档的话,你可以使用: 


‘early binding 早期绑定 


Dim wordObj As Word.Application 






Set wordObj = GetObject("C:\Invite.doc") 


如果要访问一个正在运行的Office应用程序对象,那么可以将第一个参数空出: 


Dim excelObj As Object 


Set excelObj = GetObject(, "Excel.Application") 






当你调用不带第一个参数的GetObject函数时,它就会返回一个对该应用程序示例的引用,如果该 


应用程序没有启动的话,就会产生错误。 






17.打开存在的 Word 文档 






下面的过程CenterText示范了GetObject函数的使用,访问Invite.doc文件。回想一下,该文件是 


在本章前面的过程WriteLetter里创建的。过程CenterText会将指定Word文档里的第一段居中。该 


过程使用了一个叫做DocExists的自定义函数来检查指定的文件是否存在。另外一个自定义函数 


(IsRunning)检查Word是否已经在运行。基于上述检查结果,使用CreateObject或者GetObject 


函数。如果出现错误,那么错误编号和错误描述将会显示出来。 


Sub CenterText() 


      Dim wordDoc As Word.Document 


      Dim wordAppl As Word.Application 


      Dim mydoc As String 


      Dim myAppl As String 


      On Error GoTo ErrorHandler 


      mydoc = "C:\Invite.doc" 


      myAppl = "Word.Application" 


      'first find out whether the specified document exists 首先查明该文档是否存在 


      If Not DocExists(mydoc) Then 


           MsgBox mydoc & " does not exist." & Chr(13) & Chr(13) _ 






           & "Run the WriteLetter procedure to create " & mydoc & "." 


           Exit Sub 


      End If 


      'now check if Word is running 现在检查Word是否正在运行 


      If Not IsRunning(myAppl) Then 






           MsgBox "Word is not running - will create a new instance of _ 


           Word. " 






           Set wordAppl = CreateObject("Word.Application") 


           Set wordDoc = wordAppl.Documents.Open(mydoc) 


      Else 






           MsgBox "Word is running - will get the specified document. " 


           'bind the wordDoc variable to a specific Word document 将变量wordDoc绑定到 






                                            178 




----------------------- Page 196-----------------------


            特定的Word文档 


            Set wordDoc = GetObject(mydoc) 


      End If 


      'center the 1st paragraph horizontally on page 将第一段水平居中 


      With wordDoc.Paragraphs(1).Range 


            .ParagraphFormat.Alignment = wdAlignParagraphCenter 


      End With 


      wordDoc.Application.Quit 


      SaveChanges:=True 


      Set wordDoc = Nothing 


      Set wordAppl = Nothing 






      MsgBox "The document " & mydoc & " was reformatted." 


      Exit Sub 


ErrorHandler: 






      MsgBox Err.Description, vbCritical, "Error: " & Err.Number 


End Sub 






Function DocExists(ByVal mydoc As String) As Boolean 


      On Error Resume Next 


      If Dir(mydoc) < > "" Then 


            DocExists = True 


      Else 


            DocExists = False 


      End If 


End Function 


Function IsRunning(ByVal myAppl As String) As Boolean 






      Dim applRef As Object 


      On Error Resume Next 


      Set applRef = GetObject(, myAppl) 


      If Err.Number = 429 Then 


            IsRunning = False 


      Else 


            IsRunning = True 


      End If 


      'clear object variable 清除对象变量内容 


      Set applRef = Nothing 


End Function 






18.使用关键字 New 






除了使用CreateObject函数来引用到其它的应用程序之外,你可以使用关键字New。关键字New告诉 


VB创建一个对象的新示例,返回到该示例的引用,以及将引用赋予该对象变量。例如,你可以按下 


面的方式使用关键字New: 


Dim objWord As Word.Application 


Set objWord = New Word.Application 






Dim objAccess As Access.Application 


Set objAccess = New Access.Application 






使用关键字New声明的对象变量总是早期绑定的。使用关键字New比使用CreateObject函数更高效。 


你每次使用关键字New的时候,VB就会创建应用程序的一个新示例。如果该应用程序以及运行,你 


就不需要打开另外一个示例,你应该使用GetObject函数。关键字New也可以用来在声明对象变量的 


时候,同时创建一个新的对象示例,例如: 


Dim objWord As New Word.Application 






                                             179 




----------------------- Page 197-----------------------


注意,当你使用关键字New在Dim语句里声明对象变量的时候,你就不需要使用Set语句了。然而, 


不建议使用这种创建对象变量的方法,因为当该对象变量真正被创建后,你就失去对它的控制了。 


在声明中使用关键字New会导致创建对象,即使它没有被使用到。因此,如果你想要控制创建的对 


象变量,那么总是使用下述语法声明你的对象变量吧: 


Dim objWord As Word.Application 


Set objWord = New Word.Application 


Set语句可以进一步在你需要使用该对象的地方使用,接下来的章节将示范如何使用关键字New来创 


建Microsoft Outlook的新示例,并且编写你的联系地址到Excel工作表中。 






19.使用自动控制访问 Microsoft Outlook 






要从Excel直接访问Outlook的对象模型的话,首先就要建立对Microsoft Outlook 10.0或者9.0 


Object Library的引用。下面的程序例子将在Excel工作表里插入你Outlook里面的联系信息。 


Sub GetContacts() 


      Dim objOut As Outlook.Application 


      Dim objNspc As NameSpace 


      Dim objItem As ContactItem 


      Dim Headings As Variant 


      Dim i As Integer ' array element 数组成员 


      Dim r As Integer ' row index 行号 


      r = 2 


      Set objOut = New Outlook.Application 


      Set objNspc = objOut.GetNamespace("MAPI") 






      Headings = Array("Full Name", "Street", "City", _ 


           "State", "Zip Code", "E-Mail") 


      Sheets(1).Activate 


      For Each cell In Range("A1:F1") 


           cell.FormulaR1C1 = Headings(i) 


           i = i + 1 


      Next 






      For Each objItem In objNspc.GetDefaultFolder _ 


           (olFolderContacts).Items 






           With ActiveSheet .Cells(r, 1).Value = objItem.FullName 


                 .Cells(r, 2).Value = objItem.BusinessAddress 


                 .Cells(r, 3).Value = objItem.BusinessAddressCity 






                 .Cells(r, 4).Value = objItem.BusinessAddressState 


                 .Cells(r, 5).Value = objItem.BusinessAddressPostalCode 






                 .Cells(r, 6).Value = objItem.Email1Address 


           End With 


           r = r + 1 


      Next objItem 


      Set objItem = Nothing 


      Set objNspc = Nothing 


      Set objOut = Nothing 


End Sub 


过程GetContacts开始声明一个叫做objOut的对象变量来存储到Outlook应用程序的引用,该变量定 


义为明确的对象类型(Outlook.Application),因此VBA使用早期绑定。 


注意在该过程里,我们使用关键字New(在前面部分由讨论)来创建一个新的Outlook应用程序对象 


示例,返回引用到该示例,并且将该引用赋予声明的变量objOut。 


为 了 访 问 Outlook 里 的 联 系 项 目 , 你 也 需 要 声 明 对 象 变 量 来 引 用 Outlook 的 


NameSpace 和 


ContactItem。NameSpace对象代表了储存为MAPI(信息应用程序编程界面)的信息。NameSpace对 






                                           180 




----------------------- Page 198-----------------------


象包含了文件夹(联系地址,日志,任务,等等),每个文件夹由一次有它们的项目。一个项目是 


Outlook的一个详细数据,例如邮件信息,或者联系地址。 


使用For…Each…Next循环在工作表里写入列标题之后,过程使用另外一个For…Each…Next循环来 


遍历联系地址文件夹中的项目。GetDefaultFolde方法返回一个联系地址文件夹的对象变量,该方 


法有一个参数,该常量代表了你要访问的文件夹。当所有的联系地址都被写入Excel工作表后,该 


过程释放所有对象变量,将它们设定为Nothing。 


注意,当你运行过程GetContacts时,你可能会看到一个警告信息,告诉你程序试图访问电子邮件 


地址,点击确定允许操作。 






20.接下来…… 






在本章,你学习了如何从VBA程序里启动、激活和控制其它应用程序(Word和Outlook)。你学习了 


如何使用SendKeys方法发送按键到另一个应用程序。你也学习了如何手动和编程地添加链接和嵌入 


对象。最后,你使用自动控制从Excel里创建新的Word文档,以及后来访问该文档并设置一些格式。 


你 也 学 习 了 如 何 从 Outlook 里 获 取 联 系 地 址 并 放 置 到 Excel 工 作 表 中 。 你 使 


用 两 个 新 函 数 


CreateObject和GetObject扩展了你的VBA知识。你也学习了如何以及何时使用关键字New。请在第 


十五章里学习如何从Excel里控制Microsoft Access。 


在下一章,你将学习如何通过自定义窗体从用户处收集更多的数据。 






                         第十章 对话框和自定义窗体 






   在第四章,你学习了如何使用Excel内置的InputBox函数在VBA过程执行期间从用户处收集单一 


数据。但是,万一你的程序在运行时需要多个数据怎么办呢?用户也许希望一次就提供所有数据, 


或者从项目清单中作出所有合适的选择。如果你定程序必须收集数据的话,那么你可以: 


•  使用内置对话框集合 


•  创建一个自定义窗体 


本章将教你如何从VBA过程里显示内置的对话框,以及从零开始设计你自己的自定义窗体。 


Excel对话框 


在开始创建自己的窗体之前,你应该花上一些时间学习如何利用Excel内置的对话框,这些内置对 


话框本来就是为我们准备的。我讲的不是手动选择适合的选项,而是从你自己的VBA过程里调用这 


些对话框。 


Excel有一个特殊的内置对话框集合,它们用开头为xlDialog的常量表示,例如xlDialogClear, 


xlDialogFont,xlDialogDefineName和xlDialogOptionsView。这些内置对话框是Excel对象,属于 


内置Dialos集合,每个dialog对象代表一个内置对话框。 


表10-1 常用的内置对话框 


对话框名称                   常量 


新建                      xlDialogNew 


打开                      xlDialogOpen 


另存为                     xlDialogSaveAs 


页面设置                    xlDialogPageSetup 


打印                      xlDialogPrint 


字体                      xlDialogFont 






按照下述格式使用Show方法来显示对话框: 


Application.Dialogs(常量).Show 


例如,下面的语句显示字体对话框: 






Application.Dialogs(xlDialogFont).Show 


如果你在对象浏览器里面选择Excel库后,再输入xlDialog搜索的话,那些代表Excel内置对话框的 


常量清单就会显示在对象浏览器里面了(参见图10-1) 


1. 打开一个新工作簿并且保存为Chap10.xls 


2. 切换到VB编辑器窗口 


3. 打开立即窗口 






                                  181 




----------------------- Page 199-----------------------


4. 输入下述语句并查看结果: 






Application.Dialogs(xlDialogClear).Show 






Application.Dialogs(xlDialogFont).Show 


Application.Dialogs(xlDialogFontProperties).Show 






Application.Dialogs(xlDialogDefineName).Show 


Application.Dialogs(xlDialogOptionsView).Show 


最后一句指令显示“选项”对话框的“视图”。显示内置对话框后,你可以选择合适的选项,然后 


Excel就会将当前被选择的单元格,区域或者整个工作表设置相应的格式。 


尽管你不能更改内置对话框的外观和行为,但是当你从你的VBA过程显示内置对话框的时候,你可 


以决定它的初始设置。如果你不更改初始设置,那么VBA将显示对话框和其缺省设置。 


假设你要显示清除对话框,并且所有按钮都被选择上。通常Excel显示对话框的时候,内容选项按 


钮是被选择上的。在立即窗口里输入下列语句: 


Application.DialogS(xlDialogClear).Show 1 


你可以在Show方法后面加上一系列的参数,在清除对话框里,“全部”选项按钮出现在四个选项按 


钮组的最开头。Excel通常将可用的选项进行编号,因此,“全部”=1,“格式”=2,“内容”=3,以 


及“批注”=4。在线帮助可以搜索到内置对话框的参数列表(参见图10-3) 






图10-1 前缀为“xlDialog”的常量识别Excel内置对话框 


在立即窗口里输入下面的语句,可以显示字体对话框,并且当前选择为“Arial”字体和14字号: 






Application.Dialogs(xlDialogFont).Show "Arial", 14 


如果只要明确字号的话,那么可以在第一个参数的位置放置一个逗号就行: 


Application.Dialogs(xlDialogFont).Show , 8 






下面的指令显示“定义名称”对话框,并且在工作簿中的“名称”文本框中输入“John”,“引用位 


置”里引用到单元格A1: 






Application.Dialogs(xlDialogDefineName).Show "John", "=$A$1" 


如果你点击确定Show方法就返回True,点击取消则为False。 






                                     182 




----------------------- Page 200-----------------------


图10-2 以常量xlDialogOptionsView代表的“选项”对话框“视图”的可用设置 






图10-3 Excel内置对话框参数列表 






1.文件打开和另存为对话框 






OfficeXP中一个新而功能强大的对象是FileDialog。该对象允许你从你的VBA过程里显示文件打开 


和文件另存为对话框。因为FileDialog对象是Microsoft Office 10.0 Object Library的一部分, 






                                    183 




----------------------- Page 201-----------------------


所以它在所有的Office XP应用程序里都是可用的。在前期的Excel版本中,程序员使用了两种特殊 


的方法来显示文件打开和文件另存对话框,这些方法(GetOpenFilename和GetSaveAsFilename)将 


在本章后面解释。要在你的VBA过程里面使用新的FileDialog对象来显示文件打开对话框的话,你 


可以输入下列语句: 


Application.FileDialog(msoFileDialogOpen).Show 


要显示文件另存对话框的话,则使用下面的语句: 


Application.FileDialog(msoFileDialogSaveAs).Show 






现在,我们在立即窗口里输入上面的语句来看看文件打开和文件另存对话框。 


除了文件打开和文件另存为对话框之外,FileDialog对象也能够显示“浏览”对话框,列出文件和 


文件夹(参见图10-4),或者文件夹(图10-5): 


‘ browse the list of files and folders 浏览文件和文件夹清单 






Application.FileDialog(msoFileDialogFilePicker).Show 






图10-4 文件采集对话框允许用户选择一个或多个文件,该对话框显示文件和文件夹列表,并且标 


题显示为“浏览” 


‘ browse the list of folders 浏览文件夹清单 


Application.FileDialog(msoFileDialogFolderPicker).Show 






图10-5 文件夹采集对话框允许用户选择一个路径,该对话框显示目录列表,并且标题显示为“浏 


览” 


文件对话框使用的常量列在下面的表格里,前缀“mso”表明这些常量都是Microsoft Office 对象 






                                   184 




----------------------- Page 202-----------------------


模型里一部分。 






msoFileDialog常量               值 


msoFileDialogOpen             1 


msoFileDialogSaveAs           2 


msoFileDialogFilePicker       3 


msoFileDialogFolderPicker 4 






可以使用FileDialog的Filters属性来控制显示文件的类型。如果你打开文件打开对话框下面的“文 


件类型”下拉列表框时,你将看到许多可选择的文件过滤器。那里有24种预先设置好的文件过滤器, 


你也可以在该清单里添加你自己的过滤器。在立即窗口里输入下述语句,我们就可以得到缺省的文 


件过滤器数目了: 






set f = Application.FileDialog(msoFileDialogOpen).Filters 


?f.count 


FileDialog对象的过滤器储存在FileDialogFilters集合里面。我们来创建一个简单的过程,将缺 


省的文件过滤器返回到Excel工作表: 


1. 在当前VBA工程里插入一个新模块,并且重命名为DialogBoxes 


2. 在DialogBoxes代码窗口里输入下面显示的ListFilters过程: 


Sub ListFilters() 


      Dim fdfs As FileDialogFilters 


      Dim filt As FileDialogFilter 


      Dim c As Integer 


      Set fdfs = Application.FileDialog(msoFileDialogOpen).Filters 


      Sheets(3).Cells(1, 1).Select 






      Selection.Formula = "List of Default Filters" 


      With fdfs 


           c = .Count 


           For Each filt In fdfs 






                Selection.Offset(1, 0).Formula = filt.Description & _ 


                      ": " & filt.Extensions 


                Selection.Offset(1, 0).Select 


           Next 


           MsgBox c & " filters were written to Sheet3." 






      End With 


End Sub 


该过程声明了两个对象变量,变量fdfs返回对FileDialog对象里的FileDialogFilters集合的引用, 


而对象变量filt则储存对对象FileDialogFilter的引用。FileDialogFilters集合的Count属性返回 


文件过滤器的总数。之后,过程遍历过滤器集合,并且找到每个过滤器的描述和扩展名。 


使用FileDialogFilters集合的Add方法,你可以轻易地将你自己的过滤器添加到缺省的过滤器中 


去。下面修改后代工程ListFilters2示范了如何将临时文件(*.tmp)过滤器添加到过滤器清单中 


去。该过程里的最后语句将打开文件打开对话框,因此你自己可以检查自定义的过滤器是否已经被 


添加到了文件类型下拉列表框里。 


Sub ListFilters2() 


      Dim fdfs As FileDialogFilters 


      Dim filt As FileDialogFilter 


      Dim c As Integer 


      Set fdfs = Application.FileDialog(msoFileDialogOpen).Filters 






      Sheets(3).Cells(1, 1).Select 


      Selection.Formula = "List of Default Filters" 


      With fdfs 






                                         185 




----------------------- Page 203-----------------------


            c = .Count 


            For Each filt In fdfs 






                  Selection.Offset(1, 0).Formula = filt.Description & _ 


                        ": " & filt.Extensions 


                  Selection.Offset(1, 0).Select 


            Next 


            MsgBox c & " filters were written to Sheet3." 






            .Add "Temporary Files", "*.tmp", 1 


            c = .Count 






            MsgBox "There are now " & c & " filters." & vbCrLf _ 


                  & "Check for yourself." 






            Application.FileDialog(msoFileDialogOpen).Show 


      End With 


End Sub 


你可以使用FileDialogFilters集合的Clear方法清除所有预设的过滤器。修改一下上面的过程,在 


添加自定义的临时文件(*.tmp)过滤器之前,清除内置的过滤器。 


当 你 从 文 件 打 开 对 话 框 里 选 择 一 个 文 件 时 , 该 被 选 择 的 文 件 名 称 和 路 径 就 会 被 


放 置 在 


FileDialogSelectedItems集合里。使用SelectedItems属性可以返回FileDialogSelectedItems集 


合。通过设定FileDialog对象的AllowMultiSelect属性为True,用户就可以同时按下Shift键或者 


Ctrl键和文件名称,选择一个或多个文件。 


接下来的过程示范了如何使用上面提及的属性,该过程打开一个新的工作簿并且插入一个列表框控 


件。允许用户选择一个以上的文件,然后被选择的文件将加入到该列表框控件里,并且加亮第一个 


文件名。 


Sub ListSelectedFiles() 


      Dim fd As FileDialog 


      Dim myFile As Variant 


      Dim lbox As Object 


      Set fd = Application.FileDialog(msoFileDialogOpen) 






      With fd 


            .AllowMultiSelect = True 


            If .Show Then 


                  Workbooks.Add 


                  Set lbox = Worksheets(1).Shapes. _ 


                        AddFormControl(xlListBox, _ 


                        Left:=20, Top:=60, Height:=40, Width:=300) 






                  lbox.ControlFormat.MultiSelect = xlNone 


                  For Each myFile In .SelectedItems 


                        lbox.ControlFormat.AddItem myFile 


                  Next 


                  Range("B4").Formula = _ 






                        "You've selected the following " & _ 


                        lbox.ControlFormat.ListCount & " files:" 






                  lbox.ControlFormat.ListIndex = 1 


            End If 


      End With 


End Sub 






                                             186 



你可能感兴趣的:(Excel,VBA)