VBA全名: Visual Basic Application
打開左上角的:文件->選項 彈出如下畫面,選擇“自定義功能區(qū)”,勾選上“開發(fā)工具”,點擊確定。Excel的頭上就會多出一個選項卡:開發(fā)工具。
另一種打開方式:
在excel頭部的任意一個選項卡里單擊右鍵,在彈出的菜單里選第三項“自定義功能區(qū)域”。也可以彈出如上畫面。
因為很多病毒是靠VBA的宏傳播,所以excel默認(rèn)禁止執(zhí)行宏,所以要執(zhí)行VBA先要允許宏啟動。在“開發(fā)工具”選項卡里點擊“宏安全性”,選“宏設(shè)置”,選中“啟用所有宏”。點擊確定按鈕,然后重啟excel(關(guān)閉excle文件再重新打開)
點擊“開發(fā)工具”中的“Visual Basic”,可以打開VBA編輯器。
VBA編輯器簡稱BE,即Visual Basic Editor
在資源管理器中并沒有“模塊”這樣的目錄結(jié)構(gòu),需要添加進去。在資源管理器中,右鍵單擊,彈出菜單中選擇“插入”,然后選擇“模塊”
雙擊資源管理器中的“模塊1”,就可以在右邊開發(fā)代碼。
點擊一個按鈕,計算execl中的公式
1、點擊“插入”,彈出表單控件,選中按鈕控件
2、選中按鈕控件后,在excel需要添加按鈕的地方,拖動鼠標(biāo)左鍵畫出按鈕,彈出設(shè)置按鈕調(diào)用宏信息的top畫面。給宏起一個方法名,然后點擊“新建”按鈕,創(chuàng)建代碼。然后進入VBA編輯器??吹饺缦麓a。而且在資源管理器中自動給我們創(chuàng)建了一個“模塊2”對應(yīng)此代碼。
宏:在VBA中編寫的一段小程序(Macro)
Cells(行,列) 單元格行列取值
編輯完代碼后保存文件,會彈出提示,我們必須把文件另存為xlsm格式文件,否者編寫的代碼無法保存。
回到excel畫面,點擊按鈕就會計算出A1+A2的結(jié)果,結(jié)果放在C1單元格中。
編輯按鈕文字 -> 右鍵單擊按鈕選第四項“編輯文字”(也可以拖動按鈕位置)
首先進入excle中的VBA編程界面,在頂部菜單欄中找到“工具”的按鈕,點擊“工具”,找到“選項”按鈕,然后進入選項的編輯界面,點擊“編輯器格式”,在右邊可以選擇字體的大小。
1、先在模塊2中創(chuàng)建一個做減法的宏代碼
2、然后新建一個按鈕,在彈出的top畫面中,把按鈕關(guān)聯(lián)到這個宏上。
這樣點擊這個新建的按鈕,C1就會等于A1-B1
區(qū)別:
VBA的變量規(guī)則與java基本一致,最大的不同有以下兩點:
1、VBA變量大小寫不敏感 xy = XY = xY
2、當(dāng)VBA程序中遇到一個新的變量名時,VBA會自動創(chuàng)建該變量,無需事先聲明。
上面的代碼x取一個固定單元格的值,程序根據(jù)單元格的值,計算對應(yīng)行的數(shù)據(jù)。
注意:因為vba定義變量不像Java有變量初始化,Java程序一旦調(diào)用沒有定義過的變量編譯會出錯。vba沒有定義變量初始化,所以調(diào)用一個不存在的變量不會報錯,他會自動創(chuàng)建這個變量,只是這個變量沒有值。(所以把一個變量名修改后,后面調(diào)用這個變量的地方一旦漏改,程序不會報錯,但是結(jié)果會出錯)
為了應(yīng)付沒有定義變量調(diào)用也不會報錯的情況,可以在程序里事先聲明程序里只使用以下變量。
強制聲明變量:
必須寫在該模塊文件的第一行寫上Option Explicit,然后在方法體中用Dim聲明,并用逗號分隔。一旦聲明dim的方法體里使用了沒有用dim聲明的變量,編譯就會報錯。
不可以被修改的變量,一旦定義成了常量,修改這個值會報編譯錯誤。代碼寫法如下:
Const p = 3.14
上述代碼for循環(huán)是:i從11循環(huán)到20,步長是1(循環(huán)一次加1)
注意:For循環(huán)結(jié)束處的 Next i,i可以省略不寫。(for循環(huán)套for循環(huán)的時候建議寫,否者不知道那個結(jié)束end是屬于哪個for循環(huán)的)
如果步長是每次增加1,step 1也可以省略不寫。其他情況例如遞減需要寫成step -1。
(使用tab鍵讓代碼縮進關(guān)系統(tǒng)一)
第一種:
While Cells(1,2) <> “”
…
Wend
第二種:(常用)
Do While Cells(1,2) <> “”
…
Loop
例子代碼:遍歷每一個sheet頁,計算每一個sheet頁面的指定表格數(shù)據(jù)
1、基本用法
下面的宏關(guān)聯(lián)按鈕后,點擊按鈕會根據(jù)A1和A2單元格的值在A3中寫入合格或不合格,以下就是if else的用例:
Sub ifElseTest()
Dim score1, score2
score1 = Cells(1, 1)
score2 = Cells(1, 2)
'當(dāng)A1和A2單元格都大于60的時候,A3單元格顯示合格
If score1 > 60 And score2 > 60 Then
Cells(1, 3) = "合格"
Else
Cells(1, 3) = "不合格"
End If
End Sub
2、如果判斷語句寫在同一行,那么可以不寫End IF,例:
If score1 > 60 Then Cells(1, 3) = "合格"
3、ElseIf:(ElseIf 是一個關(guān)鍵字)
大于:> 小于:< 大于等于: >= 小于等于:<= 不等于: <> 等于:=
與:And 或:or 非:not
字符串連接用&符號,記得字符串用&連接時,字符串與&符號之間一定要有空格,否者會引發(fā)歧義。
str1 = "a"
str2 = "b"
Cells(2, 1) = Cells(2, 1) & str1 & str2
1、設(shè)置斷點:直接在vba編輯器中找到要調(diào)試的代碼,點擊左側(cè)豎欄,生成斷點。運行程序代碼會到此處停下。
2、單步執(zhí)行 F8 (VBA編輯器點開“調(diào)試”,里面能看到所有調(diào)試方法和快捷鍵)
3、添加監(jiān)視:
4、報錯自動定位:
如果運行時代碼出錯,VBA會彈出提示出錯,點擊彈出框的“調(diào)試”,會自動定位到出錯行
Sub setCellsStyle()
'把A1到C2之間(矩形的左上角與右下角范圍)所有單元格字體變?yōu)榧t色
Range("A1:C2").Font.Color = -16776961
End Sub
根據(jù)上例發(fā)現(xiàn),Excel中每一個元素的操作都有對應(yīng)的對象,例如Cells就是操作單元格的,Range就是范圍操作單元格的,對應(yīng)的excel中各種圖形等都有固定的調(diào)用方法,但是我們不可能記住每一種圖形的調(diào)用對象,所以我們可以利用excel錄制宏的方法操作格個圖形對象,然后看錄制宏的代碼,就知道了每種對象如何調(diào)用。
Excel提供了一種記錄我們操作excel動作的“錄制宏”功能,只要我們記錄住操作excel的動作,再執(zhí)行錄制的宏,excel就會重復(fù)我們錄制的動作。我們可以查看excel生成的代碼,了解這些宏如何操作控件,從而根據(jù)這些代碼來完成我們的代碼。
例:我們想知道刪除行的代碼如何操作
1、點擊錄制宏
2、彈出我們要錄制的宏定義,可以直接點擊確定
3、我們刪除一行代碼,然后點“停止錄制”
4、發(fā)現(xiàn)我們的代碼里生成了一段這樣的代碼
Sub 宏2()
' 宏2 宏
Rows("4:4").Select
Selection.Delete Shift:=xlUp
End Sub
紅色部分就是刪除行的代碼,可以解釋為:刪除第四行(從第四行到第四行)
5、這樣我們就可以開發(fā)一個程序,把第一列單元格內(nèi)容小于10的進行行刪除。
先建立一個按鈕,關(guān)聯(lián)宏方法deleteRow()
Sub deleteRow()
'從20行遍歷到第1行(刪除應(yīng)該倒序遍歷,因為index有變化)
For i = 20 To 1 Step -1
If Cells(i, 1) <= 10 Then
'刪除第i行
Rows(i & ":" & i).Select
Selection.Delete Shift:=xlUp
End If
Next i
End Sub
VBA也把excel的各種控件分裝成了對象,可以調(diào)用這些定義好的類、屬性、方法操作控件。
這里的類、屬性、方法與Java在概念上一致。
以下是調(diào)用操作excel常用的類:(當(dāng)這些類被創(chuàng)建對象,每個對象就代表具體的excel相應(yīng)控件)
Application :正在運行的excel系統(tǒng)本身
WorkBook :代表一個打開的excel文件也成為工作簿 (打開的一個excel文件就是一個工作簿)
WorkSheet :代表一張工作表,也是一個sheet頁
Range :代表一個或多個單元格組成的內(nèi)容區(qū)域。
因為一個application中有多個工作簿,一個工作簿(WorkBook)中有多個工作表
(WorkSheet),一個工作表包含多個單元格。
所以Application類里有一個屬性是WorkBooks,他是一個集合,用來存放多個WrokBook。
WorkBook下也有一個屬性,是一個集合,用來存放工作表,這個屬性就是WorkSheets。
WorkSheet下也有一個屬性,用來存放一個單元格對象,屬性是Cells
WorkBook 工作簿 |
Application Excel系統(tǒng) |
WorkSheet 工作表
|
Range 單元格內(nèi)容區(qū)域 多個單元格對象 |
WorkBooks 存放WorkBook的集合
|
WorkSheets 存放WorkSheet的集合
|
Cells 一個單元格個對象
|
1、定義一個變量,變量類型是WorkSheet,寫法如下:
Dim w1 As WorkSheet
2、給一個屬于復(fù)雜類型的變量賦值,需要加關(guān)鍵字Set,寫法如下:
Set w1 = WorkSheets(i);
例子:
Sub test1()
'定義一個變量存放sheet對象
Dim w1 As Worksheet
Dim i
'遍歷所有sheet頁
For i = 1 To Worksheets.Count
Set w1 = Worksheets(i)
'讓每個sheet頁面的10行1列都等于自己的sheet名
w1.Cells(10, 1) = w1.Name
Next i
End Sub
WorkSheet的Add方法:在所屬工作簿的文件中新建一個工作表(sheet頁)
新建工作表例子代碼:
Sub test2()
'定義一個變量存放sheet對象
Dim w1 As Worksheet
'在本工作簿中新建一個sheet頁
Set w1 = Worksheets.Add
'設(shè)定新建工作簿名
w1.Name = "new sheet"
End Sub
1、按sheet頁所在順序取工作表對象:
例:取第二個sheet頁
Dim w1 As Worksheet
Set w1 = Worksheets(2)
2、按sheet頁名字取工作表對象
Dim w1 As Worksheet
Set w1 = Worksheets(“new test”)
過程調(diào)用用Call關(guān)鍵字,例:
Sub test3()
Dim w1 As Worksheet
Set w1 = Worksheets.Add
w1.Name = "new"
End Sub
Sub test4()
'調(diào)用過程test3
Call test3
End Sub
Call關(guān)鍵字可以省略
函數(shù)是過程的一種,在執(zhí)行結(jié)束后能將運行結(jié)果返回給調(diào)用者
函數(shù)需要不用Sub關(guān)鍵字,用Function,函數(shù)追后一行寫上:函數(shù)名 = 要返回的值
這樣調(diào)用這個函數(shù)的過程可以通過變量接受這個函數(shù)。
函數(shù)可以在excel的單元格中當(dāng)成公式使用
在單元格中可以寫入公式:
1、Len(str) 返回字符串長度
點三角箭頭運行,彈出str字符串的長度
2、Trim(str) 去除兩邊空格
3、Replace(str,a,b)把字符串str中所有a都替換成b
4、Lcase(str) 所有英文字母都編程小寫
Ucase(str) 所有英文字母都編程大寫
5、Left(str,3)把字符串str從左邊取3個字符
Right(str,3)把字符串str從右邊取3個字符
6、Mid(str,2,5) 把字符串str從第二個字符開始,取五個字符
7、InStr(str,”a”) 在str中尋找a出現(xiàn)的位置,如果沒找到返回0
InStr(3,str,”a”) 在str中,從第3個字符開始尋找a出現(xiàn)的位置
1、WorkBooks.open(文件名) 指定路徑打開excel文件
2、Close關(guān)閉操作的工作簿
上例代碼最后加入如下代碼:
wb.Close
3、新建一個工作簿
WorkBooks.Add
Cells是定位單元格用的,并不是單元格對象,單元格對象類是Range
Cells的寫法是我們平時的簡寫,如果寫全應(yīng)該是如下格式:
1、Range屬性
返回任意單元格范圍:Range(“D5”) , Range(“B3 : F7”)
也可以用下面方法定位左上角和右下角位置,定位到單元格范圍:
2、修改Range范圍內(nèi)單元格內(nèi)容
3、清除范圍內(nèi)單元格內(nèi)容
例子代碼:
4、Range的Font屬性
還有color 字體顏色 Bold字體粗細(xì) 等屬性
例子代碼:
5、Range.Interior屬性:
6、clear清除
7、Range.Merge合并單元格:將Range范圍內(nèi)單元格合并為一個單元格
Range.UnMerge拆分單元格: 將Range范圍內(nèi)單元格拆分為一個個單元格
以上代碼可以用with改寫為下面的代碼:
1、默認(rèn)直接調(diào)用的屬性是Application的屬性
代碼中我們控制一個單元格常常這么寫:
Cells(3,5) = “text”
那么Cells是誰的屬性呢?如果我們用以下寫法:
Dim w As Worksheet
Set w = Worksheets(1)
w.Cells(3,5) = “text”
那么我們知道Cells是Worksheet的屬性,而直接寫Cells,那么他是Application的屬性
等同于:
Application.Cells(3,5)=”test”
Application代表所有打開的excel工作表里,當(dāng)前正在被我們編輯的工作表(sheet),也可以理解為當(dāng)前正在顯示的工作表。Application可以默認(rèn)不寫。
同理直接調(diào)用的這個代碼:Range(“E3”)=7,這個Range屬性也是Application下的屬性。
2、Application.ActiveWorkbook:
當(dāng)前正處于激活狀態(tài)的工作簿(即活動工作簿)對象
3、Application.ActiveSheet:
當(dāng)前正處于激活狀態(tài)的工作表(即活動工作表)對象
例:記錄我們當(dāng)前工作簿的對象,在操作變化后,能找到當(dāng)初的對象
Dim w1 As Workbook, w1 As Wrokbook
Set w1 = Application.ActiveWorkbook
Set w2 = Workbooks.Add
w2.Wroksheets(1).Cells(2,2) =”a”; '操作新建工作簿的第一個工作表的2行2列單元格個
w1.Wroksheet(1).Cells(3,5) = “b” '操作當(dāng)初工作簿第一個工作表的3行5列單元格個
以上這個代碼的功能就是利用Application記住了當(dāng)初的操作文件,即使操作其他文件后,也能夠找到原來的操作文件。
4、Application.WorksheetFunction.公式名:
在VBA代碼中直接調(diào)用Excel表格公式
例如:獲取B2到D7單元格中最大的值
M = Application.WorksheetFunction.Max(Range(“B2:D7”))
也可以寫成:
Set r = Range(Cells(2,2),Cells(7,4))
M = Application.WorksheetFunction.Max(r)
5、Application.DisplayAlerts
是否顯示Excel警告框。
例如保存一個文件代碼如下:
W2.SaveAs(“xxx.xlsx”)
W2.Close
執(zhí)行第一次,很自然生成了一個xxx.xlsx文件保存到當(dāng)前目錄,但是再執(zhí)行這個程序,每次都提示是否覆蓋,用Application可以關(guān)閉這個提示,直接覆蓋。
在代碼中寫入:Application.DisplayAlerts = false
再執(zhí)行保存文件代碼,文件直接覆蓋,不再提示是否覆蓋。
記得操作完后,在調(diào)用close后,一定要再讓Application.DisplayAlerts = true,
否者excel任何操作都不在彈出提示信息。
6、Application.quit
退出excel
字符型:Dim str As String
str = “TEST”
整數(shù)型:Dim strLen As Integer
strLen = 3
變體型:不定義類型,根據(jù)賦值的數(shù)據(jù)類型定義類型(可以調(diào)整賦值來變化數(shù)據(jù)類型)
Dim str
str = “TEST”
變體類型缺點:
1、效率低,速度慢,因為程序每次都要判斷這個數(shù)據(jù)是什么類型
2、一旦單元格被設(shè)置成文本類型,從單元格抓取數(shù)據(jù),會把數(shù)字型當(dāng)成字符型處理
注意:Dim a ,b As String a是變體類型,b是整數(shù)型
Dim a As Integer, b As String a 和 b 都是整數(shù)型
+ 和 & 的 區(qū)別:
加號只能鏈接兩邊都是字符串的數(shù)據(jù),而&可以連接字符型也可以連接數(shù)字型
其他類型:
Integer:占用內(nèi)存2字節(jié),不支持小數(shù),取值范圍:-32768 到 + 32768
Long:占用內(nèi)存4字節(jié),不支持小數(shù),取值范圍:-2147483648到 + 2147483648
循環(huán)工作表最好用Long類型數(shù)據(jù)
Double:占用內(nèi)存8字節(jié),支持小數(shù),有誤差
Currency:占用內(nèi)存8字節(jié),支持小數(shù),固定4位小數(shù),數(shù)據(jù)精確。
1、特殊符號代表數(shù)據(jù)類型
Dim result As Long
Result = 30000 * 3
上面這兩行代碼會報錯,因為30000*3的結(jié)果會存放到臨時空間然后再賦值給result,即使result是Long型,能裝下這個結(jié)果,但是臨時空間是Integer,所以臨時空間報錯。之所以臨時空間是Integer型,是因為30000和3都是Integer型數(shù)據(jù),所以臨時空間會變?yōu)镮nteger型。所以我們需要讓臨時空間知道30000需要定義成Long型,寫法如下:
Dim result As Long
Result = 30000& * 3
Dim a&, b# 等價于 Dim a As Long ,b As Double
所以&作為連接符號的時候必須與左右兩邊留有空格,否者會被當(dāng)成Long類型
2、下劃線:
把很長的語句拆分成若干行書寫
3、冒號
把很多行語句拼接到同一行,不浪費空間,代碼整潔。
a1 = Cells(1, 1): a2 = Cells(1, 2): a3 = Cells(1, 3)
4、^ 冪運算
a的6次方 a ^ 6
5、 \ 只保留整數(shù)部分的除法符號
例:日期格式默認(rèn) 月日年 時分秒,日期兩邊要有#,聲明式日期
Dim d1 As Date
d1 = #1/19/2016 10:10:01 AM#
MsgBox d1
1、Date函數(shù) 顯示日期
Dim d1 As Date
d1 = Date
MsgBox d1
2、Time()函數(shù) 顯示時分秒
3、Now()函數(shù) 顯示日期+時間
4、解析時間
5、DateDiff函數(shù)
6、DateAdd函數(shù)
注意:
日期型本質(zhì)上就式一個Double型的數(shù)字,0代表1899年12月30日0時0分0秒
整數(shù)部分增減1就式增減1天,小數(shù)部分0.1代表0.1天,即2.4小時。
只返回True和False
邏輯關(guān)系運算符:
AND 并且 相當(dāng)于Java的 &&
OR 或則 相當(dāng)于Java的 ||
NOT 非 相當(dāng)于Java的 !
其他
靠條件控制,不再進行下一次循環(huán)
直接跳出一個循環(huán)結(jié)構(gòu)或一個子過程(函數(shù)),
比如退出Do While循環(huán),可以寫做Exit Do
如果是結(jié)束for循環(huán)就是 Exit For,退出函數(shù)用 Exit Sub
用Exit退出,Exit下面的代碼將不再執(zhí)行
注意:
1、Do While 可以用Exit Do結(jié)束循環(huán),While無法使用Exit結(jié)束循環(huán),所以處理循環(huán)不要用While
2、Exit 和Java中的break一樣,當(dāng)用在嵌套循環(huán)中,只能結(jié)束當(dāng)前這個循環(huán),不能結(jié)束所有循環(huán)。
直接跳轉(zhuǎn)到指定標(biāo)簽位置:
因為GoTo語句太過隨意,容易造成代碼混亂,不建議使用,只建議在處理異常中使用,如下節(jié)
這個語句的意思是:從下一句開始,一旦發(fā)生錯誤就直接跳轉(zhuǎn)到MyError標(biāo)簽處繼續(xù)運行
從下面開始,如果某行運行錯誤,就忽略它并繼續(xù)執(zhí)行
驗證數(shù)據(jù)是否是日期型,是日期型返回True
例如:驗證單元格1行1列是否是日期型:
If IsDate(Cells(1,1)) = True Then
Cells(1,1) = DataAdd(“d”,38, Cells(1,1))
End If
如果x是某種數(shù)值類型,比如Integer,Long,Single,Double,Currency等,函數(shù)返回True,如果是其他類型返回False。
返回數(shù)據(jù)類型的類名
例如:TypeName(“test”) 返回String字符串
Cbool,Cdate,CStr,Cint,CLng,CDbl,Ccur,Csng,Cbyte,Cdec
VBA中可以自動類型轉(zhuǎn)換,不加這些轉(zhuǎn)換函數(shù)也可以,但是加了會讓代碼更加清晰。
如果Double轉(zhuǎn)換成Integer會進行四舍五入,到那時他的這個四舍五入規(guī)則與我們的不同,用的是銀行家舍入法:
Excel工作表中只能存放1900年以后的日期,如果想存放更之前的日期就需要用Cstr把日期型轉(zhuǎn)換成字符型,然后存放到excel中。
VBA中的Round(x,n)也是用的銀行家舍入法,對x進行四舍五入,并保留小數(shù)點后n位數(shù)字。
如果想使用我們平時用的規(guī)則,需要用excel中的公式:
Application.WorksheetFunction.Round(x,2)
如果不是excel文件中沒有上面這個函數(shù)我們可以用Int()函數(shù)幫忙實現(xiàn)四舍五入的功能
Int(x)函數(shù),返回一個不大于x的最大整數(shù),例如:
所以用如下這個公式就可以實現(xiàn)四舍五入:
i = Int(x+0.5)
負(fù)數(shù)的四舍五入規(guī)則不一,本方法將-2.5舍入為-2,所以需要根據(jù)業(yè)務(wù)來確定是否符合規(guī)定
Asc(“A”) 把字符A轉(zhuǎn)換成ASCII碼
Chr(65) 把ASCII碼轉(zhuǎn)換成對應(yīng)字符
所有的字符都可以轉(zhuǎn)換成數(shù)字來表示,ASCII就是一種編碼格式。
所以字符和數(shù)字可以靠上面的兩個函數(shù)來回轉(zhuǎn)換
用途:
1、如果需要在字符串中加入換行符,就需要用到上面的函數(shù)。例:
Str = “xxxxxxxxxxxxxxxxxx” & Chr(13) & Chr(10) & “xxxxxxxxxxxxxxxxxxx”
2、如果想把a到z打印到excel中,可以使用如下寫法:
For i=65 To 90
Cells(i-63,2) = Chr(i)
Next i
我們想把數(shù)字轉(zhuǎn)換成對應(yīng)的字母,都可以用Char函數(shù)解決
3、比較字符大小,可以讀取字符的每一個字母,用Asc函數(shù)轉(zhuǎn)換成ASCII碼,然后比較大小。
ASCII碼轉(zhuǎn)換表:
定義一個數(shù)組變量:Dim my_arr(9) As String
解釋:
1、變量后面帶括號代表是數(shù)組類型,括號里放數(shù)組最大下標(biāo),
2、數(shù)組下標(biāo)從0開始,這里會放10個數(shù)
3、字符型數(shù)組
例:
自定義數(shù)組下標(biāo):
Dim arr (3 To 6)
讓變體(因為這里沒指定數(shù)組類型 )數(shù)組arr的最小下標(biāo)為3,最大為6,改數(shù)組的元素包括 a(3) a(4) a(5) a(6)
Lbound(arr)返回數(shù)組最小下標(biāo)
Ubound(arr)返回數(shù)組最大小標(biāo)
以上兩個函數(shù)的結(jié)果可以給for循環(huán)數(shù)組開始接受位置用
Split(待拆分的字符串,分割符字符串)
將字符串按照指定分隔符拆分成多個字串,返回一個數(shù)組
Dim arr() As String
arr=Split(Cells(1,1),”,”)
下面x代表數(shù)組每一個元素,a是數(shù)組
For Each x In a
str = x
Next x
VBA讀取文件流程
1、打開文件
Open “d:\demo\client.text” For Input As #1
For Input 代表輸入。#1代表代號,這個被打開文件的代號。
2、讀取一行內(nèi)容
Line Input #1,s (讀取#1代表的文件一行記錄,每執(zhí)行一次這句代碼就會讀取一行,執(zhí)行幾次讀取幾行)
3、是否已讀取到末尾
EOF(1) 讀取#1代表的文件,如果讀取到末尾這個函數(shù)返回True
4、關(guān)閉文件
Close #1 關(guān)閉#1代表的文件
例:
1、打開寫入文本文件
Open “d:\demo\client.text” For Output As #1
寫入一個文件,如果有同名文件會覆蓋,沒有此文件會創(chuàng)建
Open “d:\demo\client.text” For Sppend As #1
追加內(nèi)容寫入文件,不會覆蓋原文件內(nèi)容
2、寫入一行
Print #1 “xxxxx”; 莫非帶分號,再次寫入,同行追加
Print #1 “xxxxx” 末尾空白,再次寫入,字符會換行
3、關(guān)閉文件
Close #1
讀取目錄下所有文件
打開一個目錄,目錄結(jié)尾必須是“\”,f是返回的一個文件名
f = Dir("c:\testfile\")
然后每執(zhí)行一次f = Dir都返回一個目錄下的文件名
Sub test8()
Dim f As String
f = Dir("c:\testfile\")
Do While f <> ""
MsgBox f '彈出文件名
f = Dir '讀取下一個文件名
Loop
End Sub
打開一個目錄下所有excel文件轉(zhuǎn)換成Wrokbooks對象:
Set w = Wrokbooks.Open(path & fileName)
讀取指定文件
只想打開xlsx結(jié)尾的文件:
用這個判斷語句 If Lcase(Right(fileName,5)) = “.xlsx”
更高級的寫法:
fileName = Dir(“d:\test\*.xlsx”)
判斷目錄是否存在
判斷文件是否存在
Dir(“目錄文件名”)返回空字符串證明沒有這個文件
返回目錄和子目錄下所有文件名:
只返回一層子目錄
f = Dir(“D:\test\”,”vbDirectory”)
返回目錄下所有文件和所有子目錄文件:
需要用到遞歸方法
判斷是文件夾:
GetAttr(“file dir”) And vbDirectory = vbDirectory
Range代表單元格區(qū)域?qū)ο?(可以理解為單元格二維數(shù)組)
1、Range.Row 該Range左上角單元格的行號
2、Range.Column 該Range左上角單元格的列號
3、Range.Address該Range各個對焦頂點的絕對引用地址。
Set r = Range(“B3:D9”) r.Address返回“$B$3:$D$9”
注意:
當(dāng)Range包含多個矩形區(qū)域時,Row和Column只返回其中某一個矩形的左上角位置,并不一定是整個Range的左上角。
比如Range(“D3:E4,A1:B2”)的Row和Column返回的可能是第3行第4列,而非第一行第一列
1、Range.Count 該Range中的單元格數(shù)量
注意:Range對象由多個矩形區(qū)域構(gòu)成時,個矩形相互重疊的單元格會被重復(fù)計算。
Count計算的其實是對象而非單元格個數(shù),而且當(dāng)數(shù)量太大時會發(fā)生溢出錯誤,所以計算單元格格最安全的方法是Range.Cells.CountLarge
2、Range.Rows 容納了該Range中的每一行,可以使用Range.Rows(n)得到一個新的Range對象,代表該區(qū)域第n行的所有單元格。
注意:如果Range是由多個矩形區(qū)域構(gòu)成,Rows只代表其中某一個矩形區(qū)域的所有行。
例子:Set a = Range(“C4:E12”)
a.Select '將Range對象全部選中(方便看現(xiàn)象)
Set rw = a.Rows(2) '把Range中的第二行全部取出,rw對象還是一個Range
3、Range.Columns 容納了該Range中的每一列,可以使用Range.Columns(n)得到一個新的Range對象,代表位于該區(qū)域第n列的所有單元格。
4、Range.Cells(1,1) 取Range范圍內(nèi)的第一行第一列單元格
1、代表工作表(sheet)中全部單元格的對象
WorkSheet的屬性Cells
取得最大行號:ActiveSheet.Cells.Rows.Count
2、代表工作表(sheet)中全部被使用過的單元格(有效單元格,包含所有數(shù)據(jù))Range對象
WorkSheet的UsedRange屬性
返回一個矩形區(qū)域的Range對象,正好能夠容納這個工作表中所有使用過的單元格。
注:即使一個單元格修改過格式?jīng)]有填寫內(nèi)容也會被認(rèn)為是被使用過,有些情況下單元格內(nèi)容被刪除清空后仍可能被認(rèn)為是使用過的。
例子代碼:把使用過的單元格選中
獲取該行最后一行的行號:r.Row + r.Rows.Count -1 (左上角起始行號+Range范圍行數(shù)-1)
如果我們的表格中有大量的單元格要讀取,用平時我們用的Cells一個個單元格個讀取效率將會非常低下,所以我們可以把要讀取的單元格范圍(Range)轉(zhuǎn)化成二維數(shù)組,然后讀取數(shù)組獲得內(nèi)容。
二維數(shù)組 Dim arr(3,5) As Long 有4行6列個元素(起始位置從0開始)
如果只想二維數(shù)組返回三行五列并且從1開始,可以寫成
Dim arr(1 To 3, 1 To 5) As Long
Ubound(arr,1) 二維數(shù)組第1行數(shù)據(jù)的最大下標(biāo)
Lbound(arr,1) 二維數(shù)組第1行數(shù)據(jù)的最小下標(biāo)
把Range對象轉(zhuǎn)換為二維數(shù)組的寫法:
Dim arr()
arr=Range(“A2:C3”)
注意:Range轉(zhuǎn)換成二維數(shù)組,數(shù)組的下標(biāo)是從1開始(與Cells的下標(biāo)規(guī)則一樣)
例:
1、如果讀取的范圍操作Range的返回會發(fā)生下標(biāo)越界錯誤
2、截取Range的數(shù)組,聲明的時候必須是動態(tài)數(shù)組(數(shù)組后面的括號里不寫下標(biāo)范圍)
3、這個數(shù)組必須是變體類型,不能聲明成具體數(shù)據(jù)類型。
4、Range中即使只有一行數(shù)據(jù),轉(zhuǎn)化成數(shù)組后也是二維數(shù)組,是一個1行多列的二位數(shù)組。
把數(shù)組寫入Range中
Dim s(2,3) As Integer
S(0,0)=1 : S(0,1)=2: S(0,2)=3: S(1,0)=4 : S(1,0)=5: S(1,0)=6
Range(“b2:e4”) = s
如果想把一個維數(shù)組放到execel的一列中,需要使用矩陣轉(zhuǎn)置函數(shù)
Range(“c2:f2”) = Application.Transpose(s)
Range的結(jié)構(gòu)可以理解成一個二維數(shù)組的結(jié)構(gòu),我們可以用雙重循環(huán)遍歷Range,如果我們不關(guān)心Range每個單元格的具體行號,只是單純的遍歷處理,那么我們可以用Each方式遍歷Range的每一個單元格。
例:取出所有被使用的單元格,單元格個內(nèi)容是紅色的相加
Dim r As Range,r1 As Range
Set r = w.UsedRange '取出所有被使用的單元格
For Each r1 In r
If r1.Font.Color = vbRed Then
s = s + r1.Value
End If
Next r1
拆分成兩個處理:(調(diào)用函數(shù))
當(dāng)Range是一個單元格時,此屬性查看單元格中是否有公式,由公式這個屬性返回True,沒有返回False
當(dāng)Range是一個單元格時,如果單元格是公式則返回公式文本,如果沒有公式則與Value屬性一樣返回單元格的內(nèi)容。
Range的Value屬性,如果單元格是公式,Value返回的是公式的結(jié)果
如果想把一個單元格設(shè)置成一個公式,F(xiàn)ormula和Value都可以:
當(dāng)我們得到一個Range對象,要遍歷Range的對象的時候下標(biāo)是從1開始,無論這個Range的單元格在sheet中的什么位置。而Cells讀取單元格的下標(biāo)都是根據(jù)單元格相對于sheet中位置定的,必須是從sheet的1,1開始。
所以遍歷Range,定義范圍可以用如下方法
把多個Range對象聯(lián)合成一個新的Range對象
Dim r As Range
Set r = Union(Range(a1:b2), Range(c1:d2), Range(e1:f2))
但是Range的區(qū)域如果有重合,新合并的Range會有重復(fù)單元格
找到同時屬于多個Range的單元格(各Range重合的部分),作為一個新的Range對象返回。下圖紫色部分就是找出的重合部分
返回一個包含了這個Range的最大連續(xù)使用區(qū)域。該區(qū)域與其他任何已使用單元格都不鄰接。如下圖通過藍(lán)色部分找到藍(lán)色區(qū)域所在表的所有單元格對象,返回一個Range對象。
例子:找到有“上海市”這幾個字的單元格,把這個單元格所在的表變色
以該當(dāng)前Range的左上角單元格為原點,生成一個指定大小的新的Range對象并返回。
上面兩句可以合并寫成:
按照Range的大小,根據(jù)指定的距離平行移動,從而得到一個新的同形狀的Range。
選中Range的第一行數(shù)據(jù)
Dim r As Range
Set r = Range("A1:H100")
r.Rows(1).Select
選中當(dāng)前sheet頁的第二行數(shù)據(jù)
Dim r As Range
Set r = ActiveSheet.Rows(2)
r.Rows(1).Select
Range.Rows與Worksheets.Rows均可以一次返回多行或多列,例如
Rows(“2:3”) 返回第二行和第三行,返回的結(jié)果還是Range
Columns(“B:E”)返回B列到E列,返回的結(jié)果還是Range
如果D6到E7已經(jīng)合并單元格,我們用For Each遍歷這個Range對象
我們會發(fā)現(xiàn)他程序還是遍歷了4次,而不是一次,程序還是認(rèn)為Range中有4格單元格。但是只有第一個單元格D6有數(shù)據(jù)(合并單元格中的數(shù)據(jù)),其他單元格都沒有數(shù)據(jù)。
結(jié)論:
1、多個單元格合并之后,仍被VBA認(rèn)為是各自獨立的單元格
2、第一個單元格的值為合并后顯示的內(nèi)容,其他單元格被認(rèn)為是空值
Range.MergeCells屬性
1、當(dāng)該Range完全合并為一個單元格時,該屬性為True
2、當(dāng)該Range完全不包含合并單元格時,該屬性為False
例如上例:Range(“d6:e7”).MergeCells = True
3、當(dāng)該Range中有合并單元格,還有一部分沒合并單元格,返回NULL
判斷是否為Null的時候要用IsNull函數(shù)
4、把一個Range對象合并單元格:
Range(“A1:B3”).MergeCells = True
同理,解除合并單元格:
Range(“A1:B3”).MergeCells = False
5、VBA還提供了合并和取消合并單元格的方法。
Range.Merge合并單元格 例: Range(“A1:B3”).Merge
Range.UnMerge 取消合并單元格Range(“A1:B3”).UnMerge
Range(“A1:B3”).Merge True這個寫法是按行合并單元格
Range(“A1:B3”).Select
讓這個Range的對象都被選中(和被鼠標(biāo)選中效果一致)
Dim r As Range
Set r = Selection
獲取鼠標(biāo)選中的單元格,返回一個Range對象
可以根據(jù)錄制宏查看復(fù)制、剪切、添加等功能,結(jié)合鼠標(biāo)選中(Select),做出很多操作excel的功能。
注意:盡量不要用Select獲取Range對象,影響性能??梢杂肅ells()等方法代替Select
提高VBA代碼的性能:
1、極可能合并不必要的Select和Selection
2、盡可能刪除不必要的屬性設(shè)置
3、盡可能減少對象中“.”的數(shù)量,用With消減“.”的調(diào)用
1、Optional 指定一個可選參數(shù)
Function mySumProduct(r As Rage, Optional useColumn As Boolean=False)
在調(diào)用此函數(shù)的時候,可以不寫這個參數(shù),不寫這個參數(shù)默認(rèn)False
IsMissing(a)函數(shù)
判斷一個可選參數(shù)a是否被提供,如果沒有提供,則返回True,否則返回False
要求:該可選參數(shù)必須是變體類型,且不能有默認(rèn)值。
例子代碼:
myFun(3, ,5)這個寫法是只傳遞第一個和第二個參數(shù)。另外還有一個更好的調(diào)用方法
2、指定參數(shù)名傳遞參數(shù):
使用 := 可以按參數(shù)名傳遞參數(shù)數(shù)值
如上例可以寫成:myFun(a:=3, c:=5)
我們常用的Msgbox(彈出對話框)就是一個可選參數(shù)
Msgbox “信息!” , 1
第二個參數(shù)就是彈出畫面的種類,只有確認(rèn)按鈕,有確認(rèn)和取消按鈕等
這些數(shù)字在VBA中有對應(yīng)的常量,例如:
Msgbox “信息!” , 1 等價于 Msgbox “信息!” , vbYesNo
Msgbox還有第三個可選參數(shù),是顯示titile信息用的
Msgbox的返回值:
i=MsgBox(“please button”,vbYesNo)
在彈出的對話框上選yes,i返回6,選no,i返回7
調(diào)用函數(shù)決定是否寫括號的三種情況:
1、沒有參數(shù):不寫
2、有參數(shù),調(diào)用語句處于一行代碼中間:寫
例1: x = myFun(3,4,5)
例2: If m myFun(3,4,5) >10 Then
3、有參數(shù),調(diào)用語句獨占一行代碼:不寫
例: Sub demo()
myFun 3, 5, 7
End Sub
之所以一行Function,不寫括號是因為程序會把這個代碼當(dāng)成eval計算(同js的eval方法)
VBA對象的默認(rèn)屬性
4、如果記不住以上規(guī)則,可以在調(diào)用函數(shù)的時候加Call
Call mySub(3,5,7)
ByRef
VBA在默認(rèn)情況下都是引用傳遞,如果把一個變量a傳遞給一個函數(shù),函數(shù)對a進行了更改,函數(shù)結(jié)束后,a變量的值也會跟誰更改,因為VBA是把a這個對象傳遞給了函數(shù)。
ByVal
如果想讓VBA值傳遞(也就是只把值傳遞給函數(shù),函數(shù)即使修改了參數(shù)的值,也不會影響函數(shù)外面的變量)代碼寫法:Sub 過程名(ByVal a As Integer)
想把一個對象賦值給一個變量必須要用Set,想把一個基本類型賦值給一個變量就不用加Set
例如: Set w = Worksheets(1)
i = 5
以上就是VBA的默認(rèn)屬性導(dǎo)致
Cells(3,2)的默認(rèn)屬性是Value,所以我們想給這個單元格賦值的時候可以直接寫Cells(3,2)=1。
當(dāng)我們寫 r = Cells(3,2)的時候,VBA不知道你是想把這個cells的Value賦值給r,還是想把這個cells對象賦值給r。所以對象型賦值要用Set標(biāo)記。
MOD相當(dāng)于java的%,求余數(shù)用
i=7 MOD 4 結(jié)果是3
取0 1 2 3的隨機數(shù): i=Int(Rnd()*4)
生成a到b之間的隨機整數(shù)公式:int(Rnd()*(b-a+1)+a)
Rnd()計算的是一個偽隨機數(shù)
生成沒有規(guī)律的隨機數(shù)需要如下操作:
用戶在Excel中的一個操作,或者Excel系統(tǒng)自身的一個變化,都可以被視作一個“事件”。Excel會隨時監(jiān)聽這些事件,并可以根據(jù)編碼的要求,在某個事件發(fā)生時自動運行對應(yīng)的VBA程序。 事件發(fā)生在哪里,代碼就要寫在哪里,如果事件是靠工作簿觸發(fā),事件代碼就要寫到工作簿文件中。 打開對應(yīng)文件后,要起固定的方法名,例如想workbook一打開就觸發(fā)事件,就要把代碼寫到ThisWorkbook這個文件里,而且方法名要叫 workbook_open() |
如下圖,在文件中選中Worksheet,在右邊就能看到所有對應(yīng)sheet的事件名稱。
工作簿常用事件
新增工作表(sheet)觸發(fā)的事件用Workbook_NewSheet,sh這個參數(shù)代表剛剛新建的工作表。
例子代碼:
新建一個工作表就自動在新建的工作表上增加一個表格:
這樣沒新建一個工作表,就會生成如下表格:
工作表常用事件
SelectionChange事件,每當(dāng)用戶選中一個新的單元格時,Selection_Change事件就會被觸發(fā)。這個事件帶有一個參數(shù)Target,代表剛剛被選中的單元格對象/區(qū)域。
例如:沒選中一個單元格,就彈出這個單元格的坐標(biāo)。
利用Range的屬性:
Range.EntireRow Range所在單元格的整個行
Range.EntireColumn Range所在單元格的整個列
做一個功能鼠標(biāo)選中這個單元格,單元格的所在行和所在列都改變顏色
效果如下,鼠標(biāo)選中哪個單元格,單元格所在行和列都變?yōu)樘焖{(lán)色。
注意:這個事件寫在哪個sheet里,就哪個sheet頁有這個事件,而不是所有sheet頁都有這個事件。
Sheet事件文件與excel的sheet頁一一對應(yīng),見下圖:
所以多個sheet頁都想要同一個事件效果,需要把實現(xiàn)效果的代碼寫在模塊里,寫一個子過程,然后每個sheet頁都調(diào)用這個子過程就可以了。
變量和過程(函數(shù))都有作用域
Private 只能被本模塊內(nèi)部的代碼調(diào)用。
Public 可以被其他模塊的代碼調(diào)用。
子過程和函數(shù)如果指明,默認(rèn)為Public
變量若不指明,默認(rèn)為Private
例如:
Private Function test()
…
End Function
Private Sub Test2()
…
End Sub
Worksheet_Change(Target)
工作表事件,修改單元格內(nèi)容,焦點離開,會觸發(fā)。(沒修改單元格內(nèi)容也會觸發(fā))
如果我們在change事件發(fā)生后又修改了單元格內(nèi)容,這樣的操作又會觸發(fā)change事件,然后就引發(fā)了事件級聯(lián),避免發(fā)生的辦法如下:
下面例子是用Application.EnableEvents=False方法解決級聯(lián)效應(yīng)