- 在主要的编程语言中, 结构体是用大括号来表示 代码段的 范围 界定的. 但是在一些比较"老的"语言中,由于历史原因, 还是使用的 是: 关键字来进行界定代码 的 结构段, 如vba中的 语法结构:
- if .. . then ... end if, if .... then ... else ... end if; if .... then .... elseif .... then .... elseif .... then.... end if
- for i=1 to 10 ... exit for.... next i
- while ..... wend
- 面向对象的编程 思想中 对象要与具体的/实际的操作者 相"绑定" ?
- 作为一个类, 实例化一个类的对象时, 默认是"没有任何 指定性 意义的" , 举个例子, 比如 开一张银行卡, 它是一个对象, 但是如果这张银行卡, 没有跟任何人实际相关联, 其实它就是一张废卡. 你只有将这张卡跟 某个人相关联, 作为 某个人的银行卡了, 这时候这个对象的意义 才变得重要起来了, 卡主会给这张银行卡 设定密码, 存钱, 取钱等等操作. 也就是说, 一个对象要跟具体的 文件/数据/操作者相 关联, 那么这个时候, 对这个对象的操作/方法/成员函数, 才会/就会 作用到具体的 实物上. 才会使对象编程有实际意义和实际效果. 比如,你创建了一个 文件类
CFile file
,那么要让这个file对象 跟实际的某个文件如: E:/MyApp/myfile.txt 相关联, 那么这个时候, 对file的操作, 如open, read, write, close等操作就是对 myfile.txt 的操作了. - 而让类对象 跟 实际操作对象 相关联的方法, 就是 在初始化/创建 一个 类对象的时候, 传入操作对象作为参数
Person p('theName', AGE)
, 或者是使用类提供的方法 来建立关联,如file.open('E:/MyApp/myfile.txt', 'a') 打开文件, 追加写内容...
- excel工作表和vba代码的关系: 在vba(ide界面)中, 执行代码(全局性的Sub foo() 过程:子程序), 执行的结果/输出/作用对象, 正是/就是与之关联的工作表.
1.excel本身内置了"内部预定义变量", 如:Worksheets, 表示所有工作表的集合
- 整数类型根据范围 ,可以为byte(0-255), long型等. 工作表 的变量类型是:
worksheet. - vba 中的字符串连接 用 &, 语句结束用 "自然的" 回车enter表示, 即一行表示一条语句,末尾不用分号
- vba支持中文过程名或函数名.所以你的 过程/函数/模块/类名等, 可以用中文来表示...
sub 工作表改名()
dim i as byte, sh as worksheet
i=0
for each sh in worksheets
i=i+1
sh.Name= chr(64+i)&"工作表"'
next sh
end sub
- vba中的iif: iif(exp, truepart, falsepart),实际上就是 c语言中的 ?: 三元运算符.
注意的是, iif always evaluates both truepart and falsepart, even though it only returns one of them
数字和字母的AScii的相互关系
数字共26个字母, 数字从1,到26, 大写字母从A - Z, 小写字母从a -z,
分别是对应数字加 64或96, 正好是 32的2倍和3倍. 所以大写字母是 从 65~ 90,
小写字母是从 97 ~ 26+96=122.
vba中数字和字母字符的相互转化的函数: chr(num+64)或 chr(num+96). 字母->数字 :
code(char).
- 字符提取函数:
left(text, num_char); mid(text, start, length); right(text,num_char) - column()函数表示光标所在列 的地址引用, 如A1, 同理row().
注意工作表/公式中的函数, 和vba中的函数可能是不一样的! char是工作表函数, chr是vba中的函数.这两种不能换用!
- 单元格的地址引用, 可以为: 相对引用A1, 绝对引用R1C1(注意是行在前列在后),混合引用, 还可以使用R[-2], R,C等形式.
单元格的引用, 更多参考: - "井号name!"表示函数名称错误, "井号value!" 表示数值/数字错误. 利用公式的"求值"计算步骤可以看到一步一步的计算过程.
- vba的数组,语法是用小括号,而不是像c语言那样用中括号,如worksheets(1).name="工作表1"
- vba中有input函数 ,那是对文件的写入字符操作,类似的有read操作.
跟c语言中的字符读写类似. 如果是输入框的话, 应该是 inputbox函数. - 声明变量的四种方式:
dim varname as type
public varname as type: 公共变量, 多个模块都可以使用的
private varname as type: 当前模块/过程中可以使用的变量, 跟dim var as type基本相同
static var as type: 在整个工程级/工作簿中都有效, 只有当工作簿关闭才会消失
:::: 当用public, private ,static 来声明变量的时候, 就不要用dim了.
- vba是一种面向函数的语言, 任何变量, 你可以在函数/过程外部定义, 但是你不能在
过程/函数外部进行赋值, 否则回报"编译错误: 无效的外部过程" 也就是说, 你要在 过程内部进行 变量的赋值.
然后, 你要在另一个过程 引用这个变量的值时, 要首先 要么首先执行 "给变量赋值的那个过程", 要么在另一个过程中 调用先前赋值的那个过程! 否则无效. - 三级关联列表 使用select case... case 1(表示是省, 2,表示市, 3表示县). end select.
使用的是字典的数据结构. - vba的调试, 没有 "开始调试"的按钮, 直接 按f8就可以单步调试了, 也可以按 ctrl +f8 运行到 当前光标所在处....
- exit sub: 可以在sub中, 使用表示直接 退出 sub 不再运行代码了. 相当于c语言中的return语句..
如何清除vim中高亮的字符串? 可以使用设置: set nohlsearch. 但是这个不是很方便, 以后再次进入 vim/gvim的时候, 该词又会高亮显示, 一个比较好的方法是: 再次搜索一个 "根本就不存在"的字符串,就好了, 那么 , 以后 你所困扰的那个高亮的字符串 就再也不会出现高亮了..... 此法甚好, 方便简单直接....
- for 循环结构,中间要用循环变量,不能直接就是 for 1 to 10, 而应该是for i=1
to 10 , 因为后面要用 next i来说明循环变量. - excel与外部数据库的交互,可以通过dao或 ado来交换. DAO是: data access object; ADO: activex data object
- excel中的按钮和控件等,可以分为窗体的按钮控件等, 和 activex控件两种. 窗体的控件主要是用来指定 运行"宏"的(宏就是过程). 任意工作表都可以使用;
而activex控件是属于 某一个 工作表的私有的. 双击activex控件可以跳到代码编辑处, 而双击窗体控件是没有反应的. - "模块"中的内容是所有工作表都可以使用的, 公用的. 而某一个工作表中的 内容对象是只供具体的某一个表来使用的.
- 函数和过程都可以使用, 通常来说, 如果是给变量赋值的, 就要使用函数,
就一定要加括号. 如果不赋值的话, 就使用过程, 就不能加括号, 如果要加括号,就要使用call关键字. - 冒号等号 ":=" 主要是用在 过程中参数的调用时,可以不按参数的默认顺序书写: 如:
msgbox title:="Please Confirm" prompt:="Be certain to close?"
- 数组声明: dim a(), b() 数组的使用: 把数组名就作为一个普通变量来使用了: a=array(1,2,3) a=array('jack','tome') 等'
数组的声明/赋值, 一定要使用 array, 而 数组元素的引用, 要用 a(0), a(1).. 下标从0开始.
a = Array(1, 2, 3)
dt = Now()
MsgBox "today is: " & dt
MsgBox a(0) &":" & a(1) & ":" & a(2)
date()只能取到日期, now()可以取到日期和时间.
调试的几个按键都跟F8相关
F8: 逐语句
shift+F8: 逐过程
ctrl+shift+F8: 跳出过程
ctrl+F8: 运行到光标处
要注意的是, datedif是工作表 公式函数, 不能在 vba编程中使用. 注意区分: 有的函数是vb函数,可以直接调用,而有些是excel函数,不能直接用
indirect函数: 他的参数应该是一个单元格的地址, 如a1, 或者"a1". 所以如果不是单元格的地址形式的话, 就会报错: #ref! 表示参数地址引用错误. 第一, 如果参数用 引号, 则表示 引用指定单元格中的 值. 如果参数没有用引号, 则表示 引用 参数a1中的表示单元格如b2单元格中的内容.., 实际上, 是 引用了两次, 所以叫 间接引用.
choose函数和if 的区别
choose和if函数类似, 都是根据第一个参数给出的条件, 在后面的系列值中取一个值出来.
- if函数, 只能有两个值, 而choose可以有多个值 , 是一个系列.
- if中的候选值, 只能是单个的值, 如果他的值是一个范围, 会报#value! 错误:
=IF(FALSE,A9,A10:A12)
而choose的 系列值中的 每一个 值, 可以是一个 单元格单元格范围, 这样可以用来进行sum求和计算. - 但是, 单元格中,不能直接返回由choose指定的单元格范围, 那样会显示 #value! 错误. 但是可以使用sum统计函数等, 如
=SUM(CHOOSE(3.6,A9,A10:A12,A9:A10, A12))
在excel中, 过程sub和函数 还是有明确的区别的. 他们采用的 关键字都不一样, 过程用sub, 函数用function. 在excel工作表工作表中只能用 函数 , 不能使用sub
为什么函数的定义 一定要使用 函数名如total = 计算公式... 这样做就是为了避免 在 单元格中, 使用公式的时候, 引起 循环引用! 即, 在引用函数的时候, 就表示 这个单元格的值就是 由 函数名 代替 返回的值.
所谓, 循环公式引用, 就是你所在的单元格 如: A1中, 输入公式, 而公式中又包含 了对A1 的引用. 这个就是 循环引用:本来你是要求 a1的值, 结果a1的值没有求出来, 你又在公式中使用/引用它. 通过 公式 审核 -> 错误检查 就能 查出循环引用.
而要避免循环, 就可以 使用过程, sub, 因为sub 不需要返回值, 直接在 sub中 就 计算结果了. 但是 sub的话, 就不能 使用在公式中 不能使用等号了, 而是直接执行 宏...
关于cells的参数引用
- cells的参数 是两个! 因为有s复数? 两个参数分别是: row_index, columnIndex.
- 在vba中, 凡是 "字符组合", 如果你不用引号括起来, 就被解释为/认为是: 一个变量, 而这个变量没有被定义时, 就会报错, 所以, 如果你要表示 "列号"的话, 凡是你没有定义为 变量的 "字符序列" 都要用双引号 括起来表示 字符串!
- 比如在cells中要表示A2单元格, 你可以 cells(2, 1), 或 cells(2, "A")
- 只有cells 属性, 没有 cell属性!
worksheets是一个集合/数组, 其中 worksheets(index/worksheets.count) 和 worksheets("工作表的标签,如worksheet1") 返回的是 worksheet对象. 他的属性有: visible =true/false. 以及 activate.等. 参考: http://www.feiesoft.com/vba/excel/xlobjSheets.htm, http://www.feiesoft.com/
cells其实是一个 属性 , 是一个 application/工作表/工作区对象的属性. 格式为 : [object]Expression. cells . 如果不指定 expression: 使用本属性时,如果不指定对象识别符,则本属性将返回代表 活动工作表中所有单元格的 Range对像
使用with, 就是对同一个对象 引用它的 多个属性进行操作的时候, 最常见的是 对单元格字体的设置: with worksheets(1). cells(1,2) .font .name="arial" .size=14 end with
默认的一个对象是 Application, 其中很多都是 application 的属性, 如 worksheets, sheets等. 这个 application对象通常会 省略.. 比如 cells 属性的对象是application, 那么可以直接使用 cells属性...而直接使用 属性, 这些 属性 返回的 可能是 对象... 注意 在 vba中, 数组也叫做 "集合". 数组 ===== 集合.... 使用方法是用 圆括号 表示..
但是要注意 很多 属性 返回的 就是 对象 , 如 返回 Range对象 .... 对vba对象 的 操作, 可以使用 属性和方法. 而且 对象的方法, 在使用时, 是不必加括号的. 这个跟c/c++ 就有些区别了!
对vba对象 的 操作, 可以使用 属性和方法. 而且 对象的方法, 在使用时, 是不必加括号的. 这个跟c/c++ 就有些区别了! 比如: worksheets(1). select. 使用对象和属性, 可以采用 "见名知义"等...更重要的是, 在vba的编辑器中, 当你 输入点号的时候, 会自动弹出 提示 该对象的方法和属性!!!
range中 如何表示 可变的单元格? 使用 range("c"& row) 因为range的参数是一个 字符串, 只要给他一个字符串 就可以符合 要求, 字符串就可以用 引号加& 加 变量的方式!
杂项
- 如果使用的是application的属性, 则这个 application可以不写 . sub 子过程 + function函数 统称 为 "过程"!!!
- 通常来说, vba中的函数(库 ) 跟工作表中的 函数(库) 是两套 独立的 , 有时不能互用. 所以 ,如果你确实 要在 vba中 使用 工作表中 的函数, 那么就用 :
application.worksheetFunction. 工作表函数(....)
的方式 来引用. - 变量/属性/对象的默认 属性是 value, 所以 cells(1,1).value = cells(1,1) 不过 有 前辈提示 , 最好不用默认的/缺省 属性, 为了程序的性能!
- 对象Range等 变量的赋值/初始化, 必须用set! 否则, 如果不用set 直接就是 : range1 = range("a1") 就会报错: 对象变量或with块变量 未设置!
Private Sub CommandButton1_Click()
Dim rg As Range
Set rg = Range("c2")
rg.Value = rg.Offset(0, -2).Value * Cells(2, 2)
End Sub
- offset( rowoffset, columnoffset) 两个参数,指定 当前单元格 的行偏移/列偏移 后的单元格...
- vba中的循环语句, 有三种: for ...next i, do ..... loop untile i>10 . while ... wend for语句, 如果有数字规律的, 就直接用 for i =1 to n .... 如果要处理的单元格没有数字规律就用 for each rg in range("单元格区域1", "a1:a10", "单元格区域3",,,,,). 比如:
Private Sub CommandButton1_Click()
Dim rg As Range
For Each rg In Range("a2:c9")
If rg <> 0 Then
rg.Value = 1#
End If
Next
With Range("a2:c7").Font
.name = "微软雅黑"
.Size = 14
.Color = RGB(red:=100, green:=10, blue:=120) // 如果 参数使用 冒号等号 这种格式的话, 就要使全部参数都 使用 这种格式, 不能 交叉/混合, 否则会报 "语法错误!"
End With
End Sub
- do 和 loop 一定要成对使用, 即: 最后有loop , 前面一定要有do , 如同 next 前面一定要有for. do ....loop 的形式有几种:
- do ....loop (后面不能那个加do) 之间 没有任何其他关键字, 没有 while , until限定条件, 如果没有if exit do 将构成无限循环
- do while ... loop 使用while来限定循环次数
- do ... loop until ... 来限定循环次数, 注意while和until的条件是相反的
- 如何在while循环的中间 次数 退出 while?
首先, 不能使用break, 或 exit while 语句, 会报错
其次, 可以 使用 三种方法 : : goto flag 标号语言; 使用 exit sub(退出当前sub) , 或 application.quit(这个有副作用, 会退出整个excel应用程序); 或改用 do while ... exit do ...loop
============================================
使用对象浏览器, 可以查看给我们提供的有哪些类/方法等 , 在 编程中, 如果不知道/ 查询 一个 对象的 方法/属性等时, 就可以使用 对象browser
- 对象 /类 是在 库文件(其实是一些文件, 如在安装目录, system32中的一些dll文件, (这些dll文件中, 就是 ms已经预定义 写好的 类/ 函数/ 枚举: enum , 结构体struct 等数据类型.) 如 excel的exe文件, vba/office/msform的dll文件) 文件中定义 和提供的. 当然这些dll是保密的,不可读的.
- 库里面 可能包含 枚举类型的 成员.
- 类的成员 包括: 属性Property (不同的属性有不同的类型, 有的是string, 有的是boolean, 有的是object).. , 子过程sub, 函数function, 和事件 event.
代表单元格的 对象 是 Range , 而不是cell,cells!
cells和range的区别?
- 都可以表示 单个 的单元格, 但是要表示 区域 - 多个单元格的话, 就只能 使用 range
- 在速度和性能上, cells 最快, range其次, 方括号最慢. 一般都不用
- 子对象: range("a1: c5").range("a2") 是指 在第一个对象的基础上进行 寻找..
- 要表示变量 , 最方便的还是 cells. cells(row, column) 中, 通常使用数字, 但是 当 列数比较大 ,不便于计算的时候, 如"BK" 的时候, 就直接 使用 字母来表示 .
range中也可以使用变量, 或 使用cells来表示变量 - 什么时候必须加 value属性? : 当 赋值 语句 两边的对象 的默认处理的 数据类型 不兼容的 时候 , 就一定要使用 value.
vba中的强制数据类型转换? c表示 convert . 转换.
都有对应的函数进行 转换, 如: Cbool, CLng, Cdec, cint, cstr, ccur, cdate
cstr 和 str : 区别是 str 有正负 前导符, 而 Cstr没有正负前导符...
vba中本身 并没有 给 字符串 什么属性和方法, 所以 计算 字符串的长度 使用的是 len全局函数. 而不是 str.len属性. 这种 "混合编程(既有函数 又有对象的思想)" 的思想 跟 java 之类的完全 面向对象编程的 思想不同. 如: msgbox len(str) , 而不是: msgbox str.len
简洁的数据类型声明后缀是: 整数%, 长整数&, 单精度! 双精度# , 字符串用$ . 这是常见的几个. 但是数据类型是很多的: byte: 1个字节; integer: 2个字节; logn:4个字节; boolean类型的 2个字节. single单精度4个字节, double双精度8个字节. 对象object 4个字节. 隐式声明的都是 variant. 可以存储任意类型的数据.
数组区域的转置?
transpose 转置, 即行和列对调, 比如原区域是 m行n列, 那么 选则 n行m列的区域 (比如: 原来是 5行2列, 转置后, 就是 2行 5列). 要转置时, 输入: transpose(a2:b6), 然后按 ctrl+shift+enter, 在原来的输入上 会自动 添加 大括号, 表示 数组功能. 但是, 不能 手动/自己去 输入 大括号, 那样是无效 的, 只会 看成是 字符串.
联想笔记本功能键, F8 上面有几个方块的, 是" 切换多任务" , 但并不是 切换 窗口. 这个 在 linux下看得比较明显, 会在当前窗口和 "activities" 之间 切换. 因为他认为有两个任务: 一个是当前窗口(是一个任务! ), 一个是 左上角的 activities... wins下没有什么效果.
vba声明变量 并初始化变量?
声明变量时 只能有两种 可能, 一种是 直接说明 变量的类型type, 另一种是 用new 一个对象, 做为 "先期对象绑定", 如果变量声明后, 再赋值,叫后期绑定.
dim dict as new Dictionary // 先期绑定
如: dim dict as object
set dict = createObject("scripting.dictionary") // 后期绑定, 就不先前声明 , 当然也可以声明, 凡是 对象 变量, 都可以声明为 object
dict(key) = item 一个条目包括: key -> 对应的 item 条目
vba中的字典的方法, 只有 6个: dict.add, remove, removeall, | keys, items, exists.
Private Sub CommandButton1_Click()
Dim dict As Object
Dim arrKeys()
Set dict = CreateObject("scripting.dictionary")
dict(1) = "abc"
dict(2) = "123"
dict(3) = "100"
dict("name") = 200
dict(5) = True
arrKeys = dict.keys
MsgBox arrKeys(3)
End Sub
with 块中, 可以是任意代码, 不一定 总是以 点号 开头 的语句, 只是说 , 在with 语句块中, 凡是 以点号开头的 该对象的 方法或属性, 可以用在 任何的 语句中,包括语句的开头, 中间 , 或结尾 都可以!