2019年11月21日星期四

003 別怕 Excel VBA其實很簡單 第3章 Excel VBA基礎語法

申明本站飛宇網 https://feiyetopro.blogspot.com/自網路收集整理之書籍文章影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]謝謝!

 別怕  Excel VBA其實很簡單


第3章 Excel VBA基礎語法




廚師做菜有做菜的正確方法,一盤菜放一包鹽肯定不行。
司機開車有應該遵守的規則,紅燈亮了不停車肯定亂套。
踢足球不能用手,打籃球不能用腳。
無規矩不成方圓,做什麼事都有應該遵循的法則。做菜鹹了,汽車亂竄了,運動員開始抱著足球滿球場亂跑了……這些都是不遵守規則的現象。
VBA程式設計也有必須遵循的規則,這一章,我們將一起瞭解VBA程式設計應該遵循的法則——VBA語法。




3.1 語法,程式設計的基礎


3.1.1 這個笑話很涼快

什麼是語法?
語文老師說:“語法就是說話的方法,正確表達應該遵循的法則。”
語法告訴我們:是媽媽煎雞蛋,不是雞蛋煎媽媽。雞蛋不能說兩片,應說兩個。

3.1.2 VBA也有語法

寫一個程式,就像寫一篇作文,不遵循語法規則,肯定要鬧笑話。
工作簿該怎麼稱呼,工作表該怎麼表示,在VBA裡都有規定,不是隨心所欲的。
所以,學習VBA應先瞭解VBA語句的表達方式,只有這樣,才能讀懂並編寫正確的代碼。

3.1.3 學習VBA語法難嗎

對很多一提到語法就頭痛的人,這是最擔心的一個問題。
學習VBA語法是一個打基礎的過程,就像練習武功前先要日日夜夜地紮馬步,練習唱歌前要天天吊嗓子。這樣的過程對多數人來說是枯燥無味的,但同時又是必須的。
VBA語法究竟難不難,就看你是否能堅持學下去。


3.2 VBA裡的資料類型

3.2.1 打醬油的故事

小A來到商店,“老闆,打一斤醬油。”
老闆:“……你拿菜籃子打醬油?”
離家不遠,五分鐘後。
“老闆,打醬油。”
“拿個小小的花椒油瓶,你真有才。”
第三次,提著水桶……
……
選不對容器,打不回醬油。菜籃子裝不了醬油;花椒油瓶裝不下一斤醬油;水桶很大,能裝醬油,但殺雞卻派上了牛刀……

3.2.2 走進Excel的商店

Excel就是一間“商店”,商店裡擺著各種各樣的資料,作為Excel的使用者,每天都在重複著打醬油的故事。
職工編號、職工姓名、身份證號、出生年月、聯繫電話等,都是在Excel裡天天打的醬油,如圖3-1所示。
圖3-1 Excel裡的數據
醬油是液體,麵條是固體,商店的老闆知道應該把誰放在桶裡,把誰放在紙箱裡。
在Excel裡,姓名、出生年月、基本工資這些不同的資料就像商店裡不同的商品,為了便於區分,Excel把它們分為不同的類型。如文本、日期、數值等。
面對這些不同類型的資料,編寫程式時,你得告訴Excel,應該選擇哪種類型的容器來保存它們,如圖3-2所示。
圖3-2 Excel裡的數據

3.2.3 VBA中有哪些資料類型

資料類型就是對同一類資料的統稱,如文本、日期、數值等。
VBA裡的資料類型有:位元組型(Byte),整數型(Integer),長整數型(Long),單精確度浮點型(Single),雙精度浮點型(Double),貨幣型(Currency),小數型(Decimal),字串型(String)
,日期型(Date),布林型(Boolean)等,如表3-1所示。

表3-1      VBA中的資料類型
  資料類型存儲
空間(位元組)
範圍描述
Byte1保存0~255的整數
Boolean2保存邏輯判斷的結果:True或False
Integer2保存-2768~32767的整數
Long4保存-2147483648~2147483647的整數
Single4負值範圍:-3.402823E38~-1.401298E-45
正值範圍:1.401298E-45~3.402823E38
Double8負值範圍:-1.79769313486232E308~-4.94065645841247E-324
正值範圍:4.94065645841247E-324~1.79769313486232E308
Currency8數值範圍:-922337203685477.5808~922337203685477.5807
Decimal14不含小數時:+/-79228162514264337593543950335
包含小數時:+/-7.9228162514264337593543950335
最小非零數字:+/-0.0000000000000000000000000001
Date8日期範圍:100年1月1日~9999年12月31日
時間範圍:0:00:00~23:59:59
String(變長)10位元組加字串長度0到大約20億個字元
String(定長)字串長度1到大約65400個字元
Object4物件變數,用來引用物件
Variant(變體型)除了定長String資料及使用者定義類型外,可以包含任何種
類的資料。如果是數值,最大可達Double的範圍;如果是
字元,與變長String的範圍一樣
用戶自訂每個元素的範圍與它本身的資料類型的範圍相同
不同的資料類型告訴Excel應該以什麼形式來保存它。
面對不同類型的資料,在程式設計時,應先告訴程式按什麼資料類型來保存或處理它,如圖3-3所示。
圖3-3 不同的資料使用不同的資料類型




練習小課堂

表3-2是某單位建立員工工資檔案時會用到的資料,你能為它們指定最合適的資料類型嗎?


表3-2           員工資訊
欄位名稱欄位說明舉例最佳資料類型
職工編號三位數編號005
職工姓名職工的姓名張一平
出生日期參加工作的年月日2003-9-1
基本工資員工的基本工資,500到3000之間,有小數2532.5
交通補貼員工的交通補貼,0到200之間,有小數125.5
加班天數一個月的加班天數(整數)8

3.3 存儲資料的容器:常量和變數

3.3.1 常量和變數

常量變數是VBA存儲資料的兩種容器。
一個醬油瓶可以打多次醬油,第一斤醬油用完了,拿到小買部滿滿的一瓶又提著回來。變數就像醬油瓶,可以隨時隨地把裡面原有的醬油倒掉,再裝入新的醬油。
常量就像袋裝醬油的包裝袋,一旦往裡面裝入醬油,就不能更換其他的醬油。
因此,無論存儲什麼類型的資料,變數都可以更換內容,重複使用,而常量不可以。這是變數和常量的區別。

3.3.2 使用變數

存儲在變數裡的資料可以更換,因此變數通常用來存儲在程式運行過程中需要臨時保存的資料或物件。
 聲明變數

就像指定瓶子的名稱和用途一樣,聲明變數就是指定變數的名稱和可以存儲的資料類型。可以用語句:
             如:
聲明為String(變長)的變數最長可以串儲約20億個字元,見表3-1,如果要聲明定長的String變數,就在聲明時指定它可以存儲的資料的長度,如:
指定變數的資料類型後,該變數只能存儲指定類型的資料,而不能存儲其他類型的資料。
 使用變數型別宣告符

只有部分資料類型可以使用型別宣告符,如表3-3所示。
表3-3    型別宣告符
資料類型型別宣告字元
Integer%
Long&
Single!
Double#
Currency@
String$
 聲明多個變數


聲明多個變數,可以寫在同一個Dim後面,變數名之間用逗號隔開。
也可以用不同的語句聲明:
 如果不指定變數類型

 什麼是Variant

Variant類型也稱為變體型。

之所以稱為變體,是因為Variant類型的變數可以根據需要存儲的資料類型改變自己的類型與之匹配。就像一個無窮大的大水缸,不管你有多少斤醬油都可以裝在裡面,不管是什麼東西都可以裝在裡面。
 為什麼要聲明變數類型

同上街打醬油一樣,儘管大水缸可以裝下任意多的醬油,但如果預先已經知道自己只打一斤醬油,你會不會選擇背著大水缸去?
相比水缸,帶著醬油瓶會走得更快。電腦也一樣,運行程式時,資料佔用的位元組越小,程式運行就越快,所以,聲明變數為合適的資料類型是一個好習慣。
Variant類型比其他資料類型佔用更大的存儲空間(見表3-1),因此,編寫VBA程式時,除非必須需要,否則應避免聲明變數為Variant類型。
 強制聲明所有變數

方法一在模組的第一句手動輸入代碼:“Option Explicit”
Step 1:插入一個模組,在代碼視窗中輸入下面的程式,如圖3-4所示。
圖3-4 強制聲明變數
Step 2:運行程式,出現提示,如圖3-5所示。
圖3-5 執行程式後出錯
方法二:按圖3-6所示設置完成後,VBA會在每個模組的第一句自動寫下“Option Explicit”而無需用戶手動輸入。
圖3-6 設置強制聲明變數
 還可以這樣聲明變數


     如:
 變數的作用域


我家廚房裡的醬油瓶只供我的家人使用,因為它只屬於我家。村頭的那口老井,誰都可以在裡面打水,因為它是全村共有的。
醬油瓶和水井的作用域不同,決定了哪些人有資格使用它。
變數的作用域決定變數可以在哪個模組或過程中使用。VBA中的變數有3種不同級別的作用域,如表3-4所示。
表3-4          變數的作用域
作用域描述
單個過程在一個過程中使用Dim或Static語句聲明的變數,作用域為本過程,即只有聲明變數
的語句所在的過程可以使用它。這樣的變數稱為本地變數
單個模組在模組的第一個過程之前使用Dim或Private語句聲明的變數,作用域為聲明變數
的語句所在模組裡的所有過程,即該模組裡所有的過程都可以使用它。這樣的變數
稱為模組層級變數
所有模組在一個模組的第一個過程之前使用Public語名聲明的變數,作用域為所有模組,即所
有模組裡的過程都可以使用它。這樣的變數稱為公開變數
圖3-7~圖3-9所示為不同類型的變數的聲明語句。
圖3-7 聲明本地變數
圖3-8 聲明模組層級變數
圖3-9 聲明公開變數
注意:公開變數必須在模組物件中聲明,在工作表、表單等物件中,即使使用Public語句聲明變數,該變數也只是模組層級變數。
 把數量存儲到變數裡


把資料存儲到變數裡,稱為給變數賦值。
如果給文本、數值、日期等資料型變數賦值,語句為:
給變數賦值後,當使用這個資料時,可以直接使用變數名稱代替對應的資料。如:
這個程式定義一個String型的變數,然後給變數賦值,最後把變數的值定入活動工作表的A1儲存格中。運行程式,結果如圖3-10所示。
圖3-10 使用變數
如果給物件變數(Object型,如儲存格)賦值,語句為:
如:
這個程式在Sheet1工作表的A1儲存格中輸入文本“歡迎來到Excel Home論壇”,運行程式,結果如圖3-11所示。
圖3-11 使用物件變數



練習小課堂

如果要聲明變數存儲表3-5中的職工資訊,請寫出聲明變數和給變數賦值的語句,把表格的內容補充完整嗎?


表3-5         變數存儲表
欄位名稱欄位說明舉例聲明變數給變數賦值
職工編號三位數編號005
職工姓名職工的姓名張一平
出生日期參加工作的年月日2003-9-1
基本工資員工的基本工資,500到3000之間2532.5
交通補貼員工的交通補貼,0到200之間125.5
加班天數一個月的加班天數(整數)8
參考答案
欄位名稱欄位說明舉例聲明變數給變數賦值
職工編號三位數編號005Dim zgbh As Stringzgbh=“005”
職工姓名職工的姓名張一平Dim zgxm As Stringzgxm=“張一平”
出生日期出生的年月日1978-9-1Dim csrq As Datecsrq=#9/1/1978#
基本工資員工的基本工資,500到3000之間2532.5Dim jbgz As Doublejbgz=2532.5
交通補貼員工的交通補貼,0到200之間(整數)125Dim jtbt As Integerjtbt=125
加班天數一個月的加班天數(整數)8Dim jbts As Bytejbts=8

3.3.3 使用常量

常量通常用來存儲一些固定的、不會被修改的值,如圓周率、個人所得稅的稅率等。
常量也需要聲明,聲明常量不但要指定常量的名稱及資料類型,還要在聲明的同時給常量賦值,並且賦值後的常量不能再重新賦值。
添加模組


如:
 常量也有作用域

同聲名變數一樣,在過程的中間使用Const語句聲明的常量為本地常量,只可以在聲明常量的過程裡使用;如果在模組的第一個過程之前使用Const語句聲明常量,該常量將被聲明為模組層級常量,該模組裡的所有過程都可以使用它;如果想讓聲明的常量在所有模組中都能使用,應在模組裡的第一個過程之前使用Public語句聲明它可參閱圖3-7、圖3-8、圖3-9。

3.3.4 使用陣列


 什麼是陣列


陣列也是變數,是同種類型的多個變數的集合。
1瓶醬油是1個變數,商店裡,貨架的第1層擺著5瓶醬油,如圖3-12所示。
圖3-12 貨架上的醬油
5瓶醬油就是5個變數。因為5個變數都是醬油,所以可以把5個變數看成是由5個元素組成的一個陣列,用“醬油”這個名稱統一稱呼它們。“醬油”是陣列的名稱,5是陣列的元素個數。
 怎麼表示陣列裡的一個元素


客人讓售貨員去貨架上取醬油:“左邊第2瓶。”
售貨員心裡默數:“1、2,對,就是你。”
索引號指明元素在陣列裡的位置,把它和其他元素區別開來。所以,客人要的這瓶醬油用VBA代碼可以表示為:
如果想表示貨架上的第4瓶醬油,代碼為:
 陣列有什麼特點


(1)陣列共用同一個名字,即陣列名稱;
(2)陣列由多個同種類型的變數組成;
(3)陣列中的元素按次序存儲在陣列中,通過索引號進行區分;
(4)陣列也是變數。



參考答案


(1)“七年級6班(12)”表示七年級6班的第12位同學。
(2)七年級6班的第35位同學用VBA代碼表示為:七年級6班(35)。
 聲明陣列


陣列有大小。陣列的大小告訴VBA,這個陣列最多可以存儲多少個元素。
初一學生報名入學後開始分班級,校長說:“七6班分50個學生”,50就確定了“七6班”這個陣列的大小:這個班最多只能有50個同學。
校長的這個舉動就是在聲明陣列。聲明陣列除了要指定陣列名稱稱及資料類型,還應指定陣列的大小。
所以,“七6班”這個陣列用VBA代碼可以這樣聲明:
 給陣列賦值


分班後,班主任老師拿著學生花名冊開始給同學編學號。1號是張青,2號是鄧成……50號是馮吉。這就是給陣列賦值的過程。
給陣列賦值,同給變數賦值一樣。
如要把“孔麗”這個字串賦給一維陣列arr中的第20個元素,代碼為:
給陣列賦值時,要分別給陣列裡的每個元素賦值,賦值的方法與給變數賦值相同。
給學生分班和編學號的過程可以用VBA代碼寫成:
聲明陣列時,也可以用一個自然數指定陣列元素的 大小,該自然數為陣列的最大索引號,如:
但是,如果在模組的第一句寫上“Option Base 1”,儘管只使用一個自然數確定陣列的大小,陣列起始索引號也是1,而不是0。




練習小課堂

試一試,用VBA代碼聲明一個10個元素的Integer類型的陣列,並將1到10的自然數保存到陣列裡,你能做到嗎?
參考答案

 陣列的維數

無論貨架上的5瓶醬油,還是七6班的50個同學,都可以把它們看成是整整齊齊排成一個橫排的元素。
第1個,第2個,第3個……第20個……第50個,總是可以這樣引用它們。
像這樣排成一個橫排的陣列,稱為一維陣列。除了一維陣列, 在VBA中還可以使用多維陣列。
貨架共有3層,每層5瓶醬油,這時,陣列裡的元素不再是排成一個橫排而是三個,或者說,這個陣列由三個一維陣列組成,如圖3-13所示。
圖3-13 三層貨架上的醬油
這樣由多個橫排組成的陣列稱為二維陣列,二維陣列可以看成由多個一維陣列組成。
買醬油的客人說:“我要第2層的第4瓶。”寫成VBA代碼就是:
 聲明多維陣列


貨價有3層,每層5瓶醬油。如果要聲明這個陣列,語句為:
這個語句可以改寫為:



練習小課堂

七年級有8個班,每班50個同學,你能聲明一個名稱為“七年級”的二維陣列保存這8個班同學的姓名嗎?如果要把七年級7班的第30個同學的姓名“張林”賦給陣列裡對應的元素,你知道代碼應該怎麼寫嗎?
參考答案

如果有3個貨架,每個3層,每層擺5瓶醬油,如圖3-14所示。
圖3-14 擺滿3層貨架上的醬油
“第2個貨架第3層的第4瓶醬油。”這也是陣列“醬油”裡的1個元素,用VBA代碼表示為:
這樣的陣列,可以視為由多個二維陣列組成,稱為三維陣列。還有四維、五維,甚至更多維的陣列。
在Excel裡,寫在一個儲存格裡的資料就像貨架上的一瓶醬油,工作表中的一行就像一層貨架,一張工作表或一個儲存格區域就是一個多層的貨架,兩張工作表就是兩個貨架,兩個工作簿就是放著相同貨架的兩個商店……



練習小課堂

如果1個學生姓名占1個儲存格,把1個存儲100個學生姓名的一維陣列“七年級”寫入Excel工作表的儲存格裡,會占多大的區域?
參考答案

因為1個儲存格存儲一個學生姓名,所以把存儲100個學生姓名的一維陣列寫入Excel工作表中應占同一行裡連續的100個儲存格,如:A1:CV1 區域。

 聲明動態陣列


如果在聲明陣列時,不能確定會往這個陣列裡存儲多少個元素,即不能預知陣列的大小,可以在首次定義陣列時括弧內為空,寫成:


Dim 陣列名稱稱()


然後在程式中使用ReDim語句重新指定它的大小。
如:A列有很多職工姓名,想把這些職工姓名存儲在陣列arr中,但預先並不知道A列的職工姓名有多少個,在定義陣列時代碼可以這樣:
用這樣的方式聲明的陣列稱為動態陣列。
注意:已經定義大小的陣列同樣可以用ReDim語句重新指定它的大小。
 其他常用的創建陣列的方式


方法一:使用Array函數創建陣列
運行上述代碼,結果如圖3-15所示。
圖3-15 使用Array函數創建陣列
方法二:使用 Split 函數創建陣列
Split 函數把一個文本字串按照指定的分隔符號分開,返回一個一維陣列,陣列最小索引號是0。
運行上述代碼,結果如圖3-16所示。
圖3-16 使用Split函數創建陣列
方法三:通過 Range 物件直接創建陣列
如果想把一個儲存格區域的值直接存儲到陣列裡,可以直接把儲存格區域的值賦給變數名。
如:
運行上述代碼,運行結果如圖3-17所示。
圖3-17 通過Range物件創建陣列
 UBound和LBound函數


使用 UBound 和 LBound 函數可以計算陣列的最大和最小索引號。
一個一維陣列arr,要想知道它的最大索引號是多少,代碼為:
如果想知道它的最小索引號,代碼為:
如果想知道陣列有多少個元素,可以使用代碼:
如:
運行上述代碼,結果如圖3-18所示。
圖3-18 使用UBount和LBound函數
如果是一個多維陣列,求它的最大或最小索引號,還需指定陣列的維數,如:
運行上述代碼,結果如圖3-19所示。
圖3-19 陣列的最大索引號
Join函數

Join函數將一個一維陣列裡的元素使用指定的分隔符號連接成一個新的字串。
運行上述代碼,結果如圖3-20所示。
圖3-20 使用Join函數
 將陣列寫入儲存格區域


如想將一維陣列arr裡的第23個元素寫入活動工作表中的A1儲存格,代碼為:
也可以將陣列裡的所有元素批量寫入一個儲存格區域:
運行上述代碼,結果如圖3-21所示。
圖3-21 將一維陣列批量寫入儲存格區域
無論是一維陣列還是二維陣列,將陣列批量寫入儲存格區域時,儲存格區域的大小必須與陣列的大小一致,如:
運行上述代碼,結果如圖3-22所示。
圖3-22 儲存格的大小必須與陣列的大小一致



3.4 集合、物件、屬性和方法

3.4.1 對象,就像冰箱裡的雞蛋

 什麼是物件

物件就是東西,是用代碼操作和控制的東西,屬於名詞。
打開工作簿,工作簿就是物件;複製工作表,工作表就是物件;刪除儲存格,儲存格就是物件……
 物件的層次結構

廚房裡放著冰箱,冰箱裡有碗,碗裡裝著早餐要吃的雞蛋。無論是廚房、冰箱、碗還是雞蛋,都是東西,都是對象,如圖3-23所示。
圖3-23 廚房的結構圖
廚房裡除了冰箱,還有消毒櫃和電鍋;冰箱裡放著裝有雞蛋的碗,還放著裝著水果的盤子和裝著牛奶的瓶子,如圖3-23所示。
圖3-24 廚房裡的多個物件
一個Excel工作簿就像一間大廚房,一個工作簿裡可以有多張工作表,一張工作表裡有多個儲存格區域,如圖3-25所示。
圖3-25 工作簿裡的物件
一個物件可以包含其他物件,同時又包含在其他物件裡,不同的物件總是這樣有層次地排列著。
集合——多個同類型的物件

集合也是物件,是對多個同種類型的物件的統稱。
冰箱裡有很多碗,無論裝著雞蛋還是瘦肉,都屬於同一類物件,可以統稱為“碗”。但是這個集合裡並沒有裝牛奶的瓶子,因為瓶子不是碗,和碗不屬於一類。
一個打開的工作簿,裡面有多張工作表,無論工作表的名稱是什麼,表裡保存什麼資料,它們都屬於工作表集合,即:Worksheets。
 怎樣取到裝雞蛋的碗

要吃雞蛋,讓孩子去取。
“去廚房,把冰箱裡裝著雞蛋的碗拿來。”碗存放的地點(廚房的冰箱裡)以及碗的特徵(裝著雞蛋)都要介紹清楚,這樣,孩子才不會弄錯。
 VBA中怎樣取到集合裡的一個物件

取到想要取的物件,稱為“引用物件”。
很多個工作簿,若干張工作表,數不清的儲存格,怎麼表示“Book1” 工作簿中“Sheet2”工作表中的“A2”儲存格?
就像取冰箱裡裝雞蛋的碗一樣,在哪間房的冰箱裡拿,拿什麼碗,都要敘述清楚。
引用物件就像引用硬碟上的檔,要按從大到小的順序逐層引用。
但並不是每一次引用物件都必須嚴謹地從第1層開始。
如果Book1工作簿是活動工作簿,前面的代碼可以寫為:
如果Sheet2工作表是活動工作表,代碼甚至還可以簡寫為:

3.4.2 物件的屬性


 什麼是屬性


每個物件都有屬性。物件的屬性可以理解為該物件包含的內容或具有的特點。
蘋果是有顏色的,顏色就是蘋果的屬性。我的衣服,衣服就是我的屬性。
Sheet2工作表的A2儲存格,A2儲存格是Sheet2工作表的屬性;A2儲存格的字體,字體是A2儲存格的屬性;字體的顏色,顏色是字體的屬性。
“的”字後面的,總是“的”字前面的物件的屬性。
在VBA中,用點(.)代替“的”字:
我的衣服→我.衣服
Sheet2工作表的A2儲存格的字體的顏色→Worksheets(“Sheet2”).Range(“A2”).Font.Color
 對象的相對性

某些物件的某些屬性,返回的是另一個物件,如Sheet1工作表的Range 屬性,返回的是e對像(即儲存格),但儲存格本身也是一種物件。作為一種物件,它也有自己的屬性,如字體(Font),而字體也是物件,也有屬性,如顏色。
物件和屬性是相對的。儲存格相對於字體是物件,相對於工作表是屬性。
如果想準確地知道Value(或其他)是方法還是屬性,可以在【代碼視窗】中將游標定位到它的中間,按F1鍵,查看説明裡的資訊,如圖3-26所示。
圖3-26 查看Value的説明資訊

3.4.3 物件的方法

 什麼是方法

方法是在物件上執行的某個操作,屬於動詞。
如剪切儲存格,剪切是在儲存格上執行的操作,就是Range物件的方法;選中工作表,選中是在工作表上執行的操作,就是Wroksheet物件的方法;保存工作簿,保存就是Workbook物件的方法……
 方法和屬性的區別

屬性返回物件包含的內容或具有的特點,如顏色、大小等。方法是對物件的一種操作,如選中、啟動等。
 怎樣分辨方法和屬性

除了通過查看説明來分辨屬性和方法,還可以在【代碼視窗】中按<Ctrl+J>複合鍵,或者在物件的後面寫上點,在自動顯示的【屬性/方法清單】中根據圖示的顏色來分辨,帶綠色圖示的項是方法,其他的都是屬性,如圖3-27所示。
圖3-27 物件的屬性/方法清單
如果在物件的後面輸入點後沒有顯示【屬性/方法清單】,則先在【選項】對話方塊的【編輯器】選項卡裡勾選【自動列出成員】核取方塊,如圖3-27所示。

圖3-28 設置自動列出成員


3.5 連接的橋樑,VBA中的運算子

程式執行的過程就是對資料進行運算的過程。不同的資料類型可以進行不同的運算,按資料運算類型的不同,VBA裡的運算子主要分為算術運算子、比較運算子、連接運算子和邏輯運算子。

3.5.1 算術運算子

算術運算子用於算數運算,返回值的類型為數值型。
3+1,5-4,6*8,7^4,這些都是算數運算。算術運算子包括+、-、*、/、\、^、Mod等,各運算子的作用如表3-6所示。

表3-6
          算術運算子及作用
運算子作用示例
+求兩個數的和5+9=14
-求兩個數的差;求一個數的相反數8-5=3-3=-3
*求兩個數的積6*5=30
/求兩個數的商5/2=2.5
\整除(兩數相除取商的整數)5\2=2
^指數運算(求一個數的某次方)5^3=5*5*5=125
Mod求模運算(兩數相除取餘數)12 Mod 9=3

3.5.2 比較運算

比較運算子用於比較運算,如比較兩個數的大小。返回值為Boolean型,只能為True或False。比較運算子及其作用如表3-7所示。

表3-7
               比較運算子及作用
運算子作用語法返回結果
等於運算式1=運算式2當兩個運算式相等時返回True,否則返回False
小於運算式1﹤運算式2當運算式1小於運算式2時返回True,否則返回False
大於運算式1﹥運算式2當運算式1大於運算式2時返回True,否則返回False
﹤=小於或等於運算式1﹤=運算式2當運算式1小於或等於運算式2時返回True,否則返回False
﹥=大於或等於運算式示1﹥=運算式2當運算式1大於或等於運算式2時返回True,否則返回False
﹤﹥不等於運算式1﹤﹥運算式2當運算式1不等於運算式2時返回True,否則返回False
Is比較兩個物件的引用變數物件1 Is 物件2當物件1和物件2引用相同的物件時返回True,否則返回False
Like比較兩個字串是否匹配字串1 Like字串2當字串1與字串2匹配時返回True,否則返回False
在圖3-29所示的成績表中,如果要知道第一條記錄中學生的總分是否達到500分,語句為:
如果要判斷B2儲存格裡的考生是否姓李,代碼為:

圖3-29 學生成績表




練習小課堂

如果想知道B2儲存格的考生姓名裡是否“剛”字,代碼該怎麼寫?
 參考答案
除了*,Like運算還可以使用其他萬用字元。VBA中的萬用字元及其作用如表3-8所示。

表3-8
            VBA中的萬用字元
萬用字元作用示例
*代替任意多個字元“李家軍” Like “*家*”=True
代替任意的一個字元“李家軍” Like “李??”=True
#代替任意的一個數字“商品5"” Like “商品#”=True
[charlist]代替位於charlist中的任意一個字元“I” Like “[A-Z]”=True
[!charlist]代替不在charlist中的任意一個字元“I” Like “[!H-J]”=False





練習小課堂

根據圖3-29所示的學生成績表,用學過的運算子,你能寫出其他運算式嗎?請任意寫出4個填在下面的表格裡,然後再繼續後面的內容。
 參考答案

運算式說明
Range(“J2”).Value﹥=500判斷J2的分數是否達到500
Range(“D3”).Value﹥90判斷D3的分數是否大於90
Range(“C4”).Value﹥Range(“D4”).Value判斷C4的分數是否大於D4的分數
Range(“B5”).Value Like“孟*”判斷B5的學生是否姓孟
Range(“B5”).Value Like “*軍”判斷B5的學生姓名是否以“軍”字結尾

3.5.3 連接運算子

連接運算子用來連接兩個文本字串,有+和&兩種,如圖3-30所示。
圖3-30 在立即視窗中使用連接運算子
+可以用作算數運算的加運算,也可以用於文本連接運算。如果+運算子兩邊的運算式都是文本字串,則執行連接運算;如果+運算子兩邊的運算式包含數值,則執行算數運算,如圖3-31所示。
圖3-31 在立即視窗中使用+運算子
當使用&運算子時,無論運算子左右兩邊是何種尖型的資料,都執行連接運算。

3.5.4 邏輯運算子

邏輯運算子用於判斷邏輯運算式的真假,參與運算的資料為邏輯型資料,返回結果為Boolean型,只能為True或False。輯邏運算子及其作用如表3-9所示。

表3-9
                邏輯運算子及作用
運算子作用語法返回結果
And執行邏輯“與”運算運算式1 And 運算式2運算式1和運算式2的值都為True時返回True,否則返回False
Or執行邏輯“或”運算運算式 1 Or 運算式2運算式1和運算式2中只要有一個運算式的值為True時返回True,否則返回False
Not執行邏輯“非”運算Not 運算式運算式的值為Ture時返回False,否則返回True
Xor執行邏輯“異或”運算運算式 1 Xor 運算式2運算式1和運算式2返回的值不相同時,返回True,否則返回False
Eqv執行邏輯“等價”運算運算式 1 Eqv 運算式2運算式1和運算式2返回的值相同時,返回True,否則返回False
Imp執行邏輯“蘊含”運算運算式 1 Imp 運算式2運算式1的值為True,運算式2的值為False時返回False,否則返回True。相當於Not運算式1 Or運算式2
圖3-29所示的學生成績表,如果想判斷第一條記錄中語文、數學兩個學科中是否有及格(大於或等於60分)的科目,語句為:
如果語文成績和數學成績分別為85分和49分,則這個運算式的計算過程可以用脫等式表示為:

3.5.5 應該先進行什麼運算


在VBA中,要先處理算術運算子,接著處理連接運算子,然後處理比較運算子,最後再處理邏輯運算子。可以用括弧來改變運算順序。
運算子按運算的優先順序由高到低的次序排列為:括弧一指數運算(乘方)一求相反數一乘法和除法一整除(兩數相除取商的整數)一求模運算(兩數相除取餘數)一加法和減法一字元串連接一比較運算一邏輯運算,如表3-10所示。

表3-10
   運算子的優先順序
優先順序運算名稱運算子
1括弧()
2指數運算^
3求相反數-
4乘法和除法*,/
5整除\
6求模運算Mod



練習小課堂
用脫等式計算出下面運算式的結果。

 參考答案



3.6.1 VBA中的函數

合理使用函數不但可以節省處理資料的時間,提高工作效率還可以降低程式設計的難度,減少編寫代碼的工作量。
作為一種程式設計語言,VBA中也有函數。
在VBA中使用VBA內置函數與在工作表中使用工作表函數類似,如想知道當前的系統時間可以用Time函數(見圖3-32)。
圖3-32 利用Time函數返回當前系統時間

3.6.2 VBA中有哪些函數

VBA中的所有函數都可以在説明裡找到,如圖3-33所示。
圖3-33 在VBA説明中查看函數
函數很多,我們並不用很精確地全部記住它們,只需大概瞭解即可,如果在編寫代碼時,忘記了某個函數的拼寫,可以在【代碼視窗】中先鍵入“VBA.”,系統會自動顯示【函數清單】供你選擇,如圖3-34所示。

3.7 控制程式執行,VBA的基本語句結構

3.7.1 If…Then 語句


 應該選擇什麼問候語

“應該選擇什麼問候語?”這是小麗的煩惱。
她帶著這個問題走進了VBA課堂……
 If語句來幫忙

針對小麗的問題,老師給她提了一個建議。
把這句VBA代碼譯為漢語就是:





練習小課堂

試一試,如果中午12點後提示下午好,你能仿照老師寫的代碼寫一個這樣的語句嗎?
 參考答案
 當需要判斷兩次時

如果時間在12點之前,提示“上午好!”,否則提示“下午好!”,像這樣的問題可以用“If…Then”來編號不同的句子。如:
相當進行兩次比較運算時,這種語句並不是最佳的選擇,可以只用一個if語句代替它:




練習小課堂

你還能用“If…Then…Else”造其他的句子嗎?
“如果活動工作表的A1儲存格為空,則提示‘沒有輸入內容’,否則提示‘已經輸入內容’”。把這個句子翻譯出來,並運行它,看自己寫對了嗎?
 參考答案

如果你不習慣閱讀一行很長的代碼,還可以把If語句寫成塊的形式,我們也不推薦將二次判斷的If語句寫成一行。

 這些代碼是怎麼工作的

“如果……那麼……否則”,If語句總是可以用這個句式來描述它的執行流程。結合這個思路,可以給If語句繪製出執行的流程圖,如圖3-35所示。
圖3-35 If語句的流程圖
你知道嗎?把程式寫在【代碼視窗】裡,將游標定位在程式的中間,可以按F8鍵逐句執行語句觀察程式的執行流程。
 更多判斷的時候


不僅要判斷時間是否大於中午12點,還要判斷是否大於下午6點。需要對條件判斷兩次以上,這是小麗遇到的新問題。
小麗帶著這個問題去求助老師,老師教給她另一種解決方法。

3.7.2 Select Case 語句

儘管使用If語句可以有效地解決多次判斷的問題,當面對在3種或更多策略中做出選擇時,使用Select Case語句會更適合。





練習小課堂

第3章3.7.2小節中的程式,如果省略Case Else子句,應該怎樣寫?
 參考答案

Select Case語句的執行流程,與If…Then…ElseIf語句一樣,可以在【代碼視窗】中按F8鍵觀察得到:程式將Select Case後面的測試運算式與各個Case子句後面的運算式列表進行對比,如果測試運算式的值在運算式列表中,則執行對應的子句,然後退出整個語句塊,執行End Select後面的語句,否則將繼續進行判斷,如圖3-36所示。
圖3-36 Select Case語句的執行流程圖
因為Select Case語句一旦找到匹配的值後即跳出整個語句塊,所以,為了減少判斷的次數,在設置條件時,應儘量把最有可能發生的情況寫在前面。




練習小課堂

表3-11是給學生成績評定等級的程式,其中有部分代碼或代碼說明沒有寫出來。請你把它補充完整,然後運行程式,看自己都寫對了嗎?
表3-11
 參考答案

學會用判斷語句選擇合適的問候語,小麗很高興。笑過之後,她驚奇地發現,原來工作中每天都在做著類似的判斷。
圖3-37所示為單位職工考核得分表。
圖3-37 職工考核得分表
現要根據考核得分,按圖3-38所示的星級評定標準為職工評定星級。
圖3-38 星級評定標準
小麗決定用Select Case語句編寫一個程式來解決這個問題。

3.7.3 For…Next 語句

小麗對自己寫的程式很滿意。
但是,在工作中需要處理的資料卻複雜得多,如圖3-38所示。
圖3-39 實際上需要處理的資料
小麗求助老師,老師說,可以使用For…Next迴圈語句批量處理。
可以結合For…Next語句的執行流程圖來理解這個程式,如圖3-40所示。
圖3-40 For…Next迴圈語句執行流程圖
For…Next語句總是寫成這樣:
老師給小麗的程式是這樣的:首先定義迴圈變數i的初值和終值分別是2和19,當程式執行到For語句時,判斷變數i的值是否大於終值19,如果不大於,則執行For和Next中間的語句,直到Next語句,再返回For語句處再次進行判斷,直到迴圈變數的值大於終值19,退出迴圈,執行Next後面的語句。




練習小課堂

(1)根據代碼說明,把表3-12中的程式補充完整,讓程式運行後,能把100以內的正奇數按1,3,5,7……的順序寫進A列的儲存格裡。
表3-12
(2)你還能用同樣的方法找出100以內能被3整除的數,並按順序寫入A列儲存格嗎?試一試。
 參考答案
(1)
(2)

3.7.4 Do While 語句

如果使用Do While語句來解決3.7.3小節中為職工評定星級的問題,可以把第一條記錄作為起點,依次判斷H列的儲存格是否為空。
如果不為空,則執行Select Case語句進行星級評定,直到儲存格內容為空退出迴圈。
還可以在結尾處判斷迴圈條件,語句為:
Do While迴圈語句是當邏輯運算式的值為False時退出迴圈,但結尾判斷式的語句是在執行一次循環體後再判斷迴圈條件,因此,當迴圈條件一開始就為False時,比開頭判斷式要多執行一次循環體,其他時候執行次數相同。




練習小課堂

試一試,用結尾判斷式的Do While語句來解決3.7.3小節中為職工評定星級的問題。
 參考答案

3.7.5 Do Until 語句

Do Until語句也有開頭判斷和結尾判斷兩種語句形式。
開頭判斷式:
結尾判斷式:
與Do While語句不同的是:Do While語句是當邏輯運算式的值為False時退出迴圈,而Do Until語句是當邏輯運算式的值為True時退出迴圈。




練習小課堂

試一試,分別用Do Until語句的兩種形式編寫程式來解決3.7.3小節中評定職工星級的問題。
 參考答案

結尾判斷式:
結尾判斷式:

3.7.6 For Each…Next 語句

當前活動工作簿中有許多工作表,但並不知道數量。如果要把所有工作表的名稱按次序寫入活動工作表的A列,For Each…Next是更適合的迴圈語句。
無論工作簿中有多少張工作表,執行程式後,都會將所有工作表的標籤名稱依次寫入當前活動工作表的A列儲存格中,如圖3-41所示。
圖3-41 把工作表標籤名稱寫入A列
使用For Each…Next迴圈語句時,不需要定義迴圈條件,如果要在一個集合或一個陣列中迴圈時,同其他迴圈語句相比,For Each…Next要靈活得多。
練習小課堂

用For Each…Next語句編寫一個程式將1到100的自然數輸入A1:A100儲存格區域。
參考答案

3.7.7 其他的常用語句


 GoTo語句,讓程式轉到另一條語句去執行

GoTO地點,譯成中文是“去到指定的地點”。在VBA中,GoTo語句也可以這樣理解。
在VBA中,指定地點可以在目標代碼所在行前加上一個帶冒號的字串或不帶冒號的數字作為標籤,然後在GoTo的後面寫上標籤名。如:
GoTo語句大多用於錯誤處理時,參閱7.4小節,因為它會影響程式的結構,增加閱讀和調試的難度,所以除非必須需要,否則應儘量避免使用GoTo語句。
 With語句,讓代碼更簡單

當需要對相同的物件進行多次操作時,往往會編寫一些重複的代碼。如:
這是一個設置A1儲存格字體的程式。因為是對同一個物件的多個屬性進行設置,所以4行代碼的前半部分都是相同的。如果你不想多次重複錄入相同的代碼,可以用With語句來簡化輸入。
合理使用With語句,不但可以減少代碼的輸入量,還能提高程式的運行效率。




3.8 Sub過程,基本的程式單元

做什麼事都有一個過程。
燒水,倒水,拿毛巾……倒水,這是洗臉的過程。買菜,洗菜,切菜,炒菜,盛菜,這是做菜的過程。打開工作簿,輸入資料,保存工作簿,退出Excel程式,這是資料錄入的過程。
過程就是做一件事情的經過,由不同的操作按先後順序排列、組合起來。

3.8.1 關於VBA過程

 什麼是VBA過程

打開工作簿,輸入資料,保存工作簿,退出Excel程式。這是一個錄入資料的過程。把這些操作寫成VBA代碼,按先後順序組合起來就是一個VBA過程。
所以,VBA過程就是完成某個給定任務的代碼的有序組合。
 VBA裡有哪些過程

VBA的基本過程有Function過程和Sub過程兩種。

3.8.2 編寫Sub過程需要瞭解的內容


 關於Sub過程

錄製的宏就是Sub過程,錄製巨集也只能生成Sub過程。
可以錄製一個複製A1:A8儲存格到C1:C8儲存格的巨集,結合巨集來認識Sub過程的結構。
知道了過程的結構,就可以依葫蘆畫瓢,像做填空題一樣隨心所欲地編寫Sub過程了。
 應該把過程寫在哪裡

宏保存在哪裡,還記得嗎?是的,模組。過程也是保存在模組裡。
和錄製的宏一樣,過程保存在模組裡,所以編寫過程,應先插入一個模組來保存它(參閱2.4.1小節),插入模組後,按兩下啟動它的【代碼視窗】,就可以在【代碼視窗】中編寫過程了。




練習小課堂

編寫過程,分別調用不同模組的私有過程和公共過程,都能調用嗎?
參考答案

可以調用其他模組中的公共過程,不能調用其他模組中的私有過程。






Function過程也稱為函數過程。編寫一個Function過程,就編寫了一個函數。
函數可以完成很多複雜的計算。如想求A列的和,可以用SUM函數;想知道A列有多少個“張三”,可以用COUNTIF函數。
Excel並沒有提供解決這個問題的工作表函數。這時,可以根據需要自己編寫一個。

3.9.1 試寫一個函數


Function過程同Sub過程一樣,都是保存在模組裡,所以,在編寫函數前,應先插入一個模組(參閱第2章2.4.1小節)來保存它。
插入模組後,按兩下模組啟動它的【代碼視窗】,即可開始編寫函數。
如果想讓函數生成一個1〜10之間的隨機整數,完整的程式為:

3.9.2 使用自訂函數


自訂的函數可以在工作表中使用,也可以在VBA過程裡使用。
 在工作表中使用自訂函數

在工作表中使用自訂函數同使用工作表函數類似,如圖3-45所示。
圖3-45 在工作表中使用自訂函數
自訂的函數可以在【插入函數】對話方塊裡找到,如圖3-46所示。
圖3-46 查看自訂函數
自訂的函數可以和其他函數嵌套使用,如圖3-47所示。
如:
圖3-47 嵌套使用自訂函數
 在VBA過程中使用自訂函數

在VBA中使用自定函數與使用VBA的內置函數一樣,如圖3-48所示。
圖3-48 在VBA中使用自訂函數

3.9.3 怎麼統計指定顏色的儲存格個數

 問題一:儲存格是什麼顏色

在Excel裡,可以通過RGB函數指定不同的顏色,如想將活動工作表中B1儲存格的網底設置為黃色,代碼為:
 怎麼統計指定顏色的儲存格個數

要知道A1:A10裡有少個黃色儲存格,可以讓VBA替我們數一下,是黃色的累計,不是黃色的排除。
在工作表裡輸入函數,可以看到函數返回的計算結果,如圖3-49所示。
圖3-49 統計黃色儲存格的個數
還可以通過色彩索引號來引用某個顏色,在Excel 2003中,預設情況下,黃色的色彩索引號為6,所以上面的代碼還可以寫為:
ColorIndex屬性引用的是某個索引號上的顏色,而Color返回的是真實顏色。因為顏色的索引號可以更改,所以使用ColorIndex屬性引用到的顏色不一定都相同,因此函數不一定能返回正確的結果。
 用參數指定計算區域

在工作表中使用函數時,可以通過函數參數指定計算統計的儲存格區域。自訂函數也可以使用參數。
如果需要統計的儲存格區域不是固定的,可以用變數代替程式裡的A1:A10儲存格區域,讓使用者在使用自訂函數時通過函數參數指定區域。
為函數設置參數後,如果要統計A1:C10中黃色網底儲存格的個數,輸入公式“=count color(A1:C10)” 即可,如圖3-50所示。
圖3-50 使用參數的自訂函數
 給自訂函數指定第2參數

還可以給函數設置第2參數,通過第2參數指定要統計的顏色。
在工作表中使用自訂的函數,如圖3-51所示。
圖3-51 用參數指定需要統計的顏色
如果需要,還可以為函數添加第3參數,第4參數……
 設置自訂函數為易失性函數

有時,當工作表重新計算之後,自訂函數並不會重新計算。如在工作表中使用第3章3.9.1小節中生成隨機的自訂函數後,按F9鍵重算工作表,函數並不會生成新的隨機值。
但如果在函數開始添加一條語句,添加語句後,無論何時重新計算工作表,函數都會重新計算,得到新的結果。
注意:使用Application. Volatile True語句是將自訂函式宣告為易失性函數。當工作表發生重算後,易失性函數會重新計算函數的值。但因為更改儲存格的背景顏色不會讓工作表重算,所以,無論是否使用該語句,更改儲存格的顏色後,本節中編寫的自訂函數CountColor都不會重新計算。

3.9.4 聲明函數過程,規範的語句


聲明Function過程的語句和聲明Sub過程的語句類似。同Sub過程一樣,Function函數也分公共函數和私有函數,如果想聲明一個私有函數,請一定要加上Private關鍵字。













程式設計就像做事,得講究條理。
先做什麼,後做什麼,安排好了,程式才不會改錯。
除了在操作上要有條理之外,也應儘量讓代碼條理清晰,便於閱讀。所以,在程式設計時,除了要遵循VBA的語法規則外,還應養成一些良好的習慣。

3.10.1 代碼排版,必不可少的習慣

兩篇同樣的稿紙,是否經過精心排版,對讀者的吸引力肯定不一樣。要想讓自己編寫的程式清晰易懂,排版的過程也必不可少。圖3-52所示為排版前後的代碼。
圖3-52 排版前後的代碼

3.10.2 怎樣排版代碼

 縮進,讓代碼更有層次

縮進可以使程式更容易閱讀和理解,在VBA中,過程的語句要比過程名縮進一定的字元,在If、Select Case、For…Next、Do…Loop、With語句等之後也要縮進,一般縮進4個空格,如圖3-53所示。
圖3-53 縮進的代碼
但在縮進某行或某塊代碼時,並不用手動在代碼前敲入4個空格,可以選中代碼塊(如果是一行,只需將游標定位到行首而不用選中它),按下Tab鍵(或依次執行【編輯】→【縮進】功能表命令)即可將代碼統一縮進一個Tab寬度,如圖3-54所示。
圖3-54 利用功能表命令縮進代碼塊
如果選中已縮進的代碼,按<Shift+Tab>複合鍵(或依次執行【編輯】一【凸出】功能表命令),則將選中的代碼取消縮進一個Tab寬度。
Tab寬度默認為4個空格,可以在【選項】對話方塊裡修改如圖3-55所示。
圖3-55 設置Tab寬度
 更改長行代碼為短行代碼

當一條語句過長時,可以在句子的後面輸入一個空格和底線(—),然後換行,把一行代碼分成兩行。如:
雖然可以把一行代碼分成兩行、三行甚至更多,但盲目分行卻不是好習慣,一般當一行代碼的長度超過80個字元時,才考慮分行。
 把多行合併為一行

在第一行代碼後加上英文冒號,可以接著寫第二行代碼。通過這樣的方式可以把多行短代碼合併成一行代碼。
儘管可以把多行代碼寫在同一行,但是這樣會給閱讀增加許多麻煩,所以除非必須需要,否則並不提倡這樣做。

3.10.3 注釋,讓代碼的意圖清晰明瞭

注釋就像商品的說明書,介紹代碼的功能及意圖。
編寫的程式有什麼用途,可以通過注釋語句作簡要介紹,讓代碼更加易讀易懂。
 添加注釋語句

注釋語句以英文單引號開頭,後面是注釋的內容。可以放在代碼的末尾,也可以單獨寫在一行,如圖3-56所示。
圖3-56 為代碼添加注釋
當注釋語句單獨成一行時,還可以使用Rem代替單引號。
相信我,多數人不出3個月就會忘記自己寫的程式碼的用途。所以,哪怕只是為自己,也應該為較為重要的代碼添加注釋。
 妙用注釋

在偵錯工具時,如果不想運行某行代碼,可以在代碼前加上單引號(或Rem),讓它成為注釋語句,而不用刪除它。當要恢復這些代碼時,只要將單引號(或Rem)刪除即可(如圖3-57所示),這個技巧在調試代碼時經常都會用到。
圖3-57 注釋某句不需要的代碼
如果要注釋或取消注釋一塊代碼,還有簡單的方法,如圖3-58所示。
圖3-58 批量添加注釋
圖3-58 批量添加注釋(續)
如果要取消注釋,把代碼還原成普通代碼,就選中注釋代碼塊,按一下【編輯】工具列中的【解除注釋塊】按鈕,如圖3-59所示。
圖3-59 批量取消注釋

0 留言:

發佈留言