VBA編程問(wèn)答(第1輯)
VBA編程問(wèn)答 (第1輯) 在學(xué)習(xí)ExcelVBA編程的過(guò)程中,經(jīng)常會(huì)遇到一些問(wèn)題,,有些可能是新碰到的,,有些則是以前已遇到過(guò)但暫時(shí)忘掉了解決辦法的,,VBA編程問(wèn)答將把我所收集到的問(wèn)題和自已所遇到的問(wèn)題及解決辦法進(jìn)行歸納整理,以方便查閱和參考,。 在下面的內(nèi)容中,,有大量的程序代碼,您可以將它們輸入或復(fù)制到VBE編輯器中進(jìn)行調(diào)試,,也可以將它們進(jìn)行適當(dāng)?shù)恼{(diào)整和修改后應(yīng)用到自已的程序中,。有些問(wèn)答提供了參考示例,您可以直接下載后處理,。 本輯目錄 問(wèn)題1:如何優(yōu)化VBA代碼并使程序盡可能快的運(yùn)行,? 問(wèn)題2:如何禁用用戶窗體的關(guān)閉按鈕? 問(wèn)題3:可以撤銷宏所執(zhí)行的操作嗎,? 問(wèn)題4:如何將同一文件夾中的多個(gè)文本文件讀入到工作簿中,? 問(wèn)題5:如何使用VBA刪除所有的空工作表? 問(wèn)題6:如何獲取計(jì)算機(jī)上可供使用的打印機(jī)列表,? 問(wèn)題7:如何基于某個(gè)單元格更新其它單元格的日期,? 問(wèn)題8:如何編寫一個(gè)宏程序運(yùn)行另一個(gè)宏程序特定的次數(shù)? 問(wèn)題9:如何在一個(gè)組合框中列出所有工作表中單元格D3中的值,? 問(wèn)題10:如何使工作表中的文本閃爍,? 問(wèn)題11:如何將工作簿中其它工作表名導(dǎo)入到指定的工作表中? 問(wèn)題12:如何在單元格中快速輸入帶秒的時(shí)間,? ===================================================================== 問(wèn)題1:如何優(yōu)化VBA代碼并使程序盡可能快的運(yùn)行,? 解答: 速度問(wèn)題一直是VBA程序值得關(guān)注的一個(gè)方面。當(dāng)您編寫了一個(gè)對(duì)大量數(shù)據(jù)進(jìn)行操作的程序后,,在運(yùn)行時(shí)可能會(huì)發(fā)現(xiàn)程序運(yùn)行得很慢,,有的甚至達(dá)好幾分鐘,就像Excel應(yīng)用程序已崩潰了一樣,。但當(dāng)您發(fā)現(xiàn)程序確實(shí)在運(yùn)行,,并得到正確的結(jié)果后,您可能就會(huì)想到如何使程序更快的運(yùn)行了,。當(dāng)然,,代碼運(yùn)行速度慢可能是VBA程序的一個(gè)缺點(diǎn),這也可能是程序語(yǔ)言本身的一個(gè)原因,,但我們也可以找到一些方法優(yōu)化VBA代碼并使程序盡可能快的運(yùn)行,。 下面是我整理的一些優(yōu)化VBA代碼或提高程序運(yùn)行速度的方法,有些方法是我們?cè)诰幊讨泻玫淖龇ê蛻?yīng)該養(yǎng)成的好習(xí)慣,,希望能帶給您一些有益的參考,。高質(zhì)量的程序和運(yùn)行效率是需要不斷實(shí)踐,并在實(shí)踐中不斷總結(jié)和積累經(jīng)驗(yàn)的,,也希望您能將在編寫程序過(guò)程中發(fā)現(xiàn)的一些優(yōu)化方法介紹給大家共享,。 1,、盡量簡(jiǎn)化代碼 通過(guò)簡(jiǎn)化代碼,可以提高程序的性能,。您可以將通用過(guò)程編寫為子過(guò)程來(lái)調(diào)用,。例如,假設(shè)有一個(gè)應(yīng)用程序需要在不同的地方實(shí)現(xiàn)查找一定范圍內(nèi)的某個(gè)特殊條目,,在一個(gè)沒(méi)有簡(jiǎn)化代碼的應(yīng)用程序中,,不同的過(guò)程可能需要應(yīng)用各自的算法以實(shí)現(xiàn)在某個(gè)范圍內(nèi)查找某一條目,修改每個(gè)過(guò)程使其采用一個(gè)更有效的算法并不是一件很容易的事,。而一個(gè)簡(jiǎn)化的程序則只有一個(gè)查找算法,,即將該查找算法編寫成通用的子程序,需要查找某個(gè)范圍的過(guò)程都調(diào)用該子程序,,通過(guò)在查找方法的子程序中優(yōu)化查找算法,,使得調(diào)用該方法的所有過(guò)程都享受性能提高所帶來(lái)的好處。 另外,,刪除所有無(wú)關(guān)的代碼,,這在所錄制宏中表現(xiàn)得尤為明顯。在錄制宏時(shí),,經(jīng)常會(huì)產(chǎn)生一些與所實(shí)現(xiàn)的功能無(wú)關(guān)的代碼,,您可以將這些代碼刪除,以使得代碼得以簡(jiǎn)化,。 在下面將要講到的設(shè)置對(duì)象變量代替長(zhǎng)對(duì)象引用,,使用With…End With語(yǔ)句、執(zhí)行For Each…Next循環(huán)語(yǔ)句,,根據(jù)程序環(huán)境盡量減少OLE引用,,等等,均是簡(jiǎn)化代碼的好方法,。 2,、強(qiáng)制聲明變量 在VBE編輯器中的菜單“工具——選項(xiàng)”對(duì)話框中“編輯器”選項(xiàng)卡中,您應(yīng)該始終保持“要求變量聲明”復(fù)選框被選中,,這樣將在模塊代碼頂部出現(xiàn)Option Explicit語(yǔ)句,,要求您在編寫代碼時(shí)對(duì)所有出現(xiàn)的變量均進(jìn)行聲明,這樣,,在使用變量時(shí)減少內(nèi)存需求并加速性能。 (1)要節(jié)省內(nèi)存資源,,必須始終用特定的數(shù)據(jù)類型聲明所有變量,。如果不使用特定的數(shù)據(jù)類型聲明變量,VBA會(huì)創(chuàng)建Variant類型的變量,,這將比任何其他數(shù)據(jù)類型要求更多的內(nèi)存,。 (2)清楚每種數(shù)據(jù)類型需要多少內(nèi)存以及它可以存儲(chǔ)的值的范圍,。除使用較小的數(shù)據(jù)類型會(huì)導(dǎo)致隱性轉(zhuǎn)換的情況外,應(yīng)始終使用盡可能小的數(shù)據(jù)類型,。例如,,因?yàn)镮nteger類型的變量將被轉(zhuǎn)換成Long類型的變量,應(yīng)該將那些存儲(chǔ)整型值的變量聲明為L(zhǎng)ong類型,,而不是Integer類型,。 (3)除非確實(shí)需要,應(yīng)避免使用浮點(diǎn)數(shù)據(jù)類型,。盡管Currency數(shù)據(jù)類型更大,,但它比 Single 數(shù)據(jù)類型快,因?yàn)镃urrency數(shù)據(jù)類型不使用浮點(diǎn)處理器,。 (4)如果在一個(gè)過(guò)程中多次引用一個(gè)對(duì)象,,可以創(chuàng)建對(duì)象變量,并將對(duì)給對(duì)象的引用指派給它,。因?yàn)閷?duì)象變量存儲(chǔ)對(duì)象在內(nèi)存中的位置,,VBA將不必再次查找其位置。 (5)將對(duì)象變量聲明為特定的類型(不是Object類型),,以便利用早期綁定,。 3、減少變量的作用范圍并及時(shí)釋放變量 主要是對(duì)象變量,,在其使用完后,,及時(shí)釋放。例如,, Dim TempObj As AnyObject,AnObj As AnyObject Set TempObj=New AnyObject Set AnObj=TempObj Set TempObj=Nothing ‘釋放對(duì)象變量 4,、盡可能使用早期綁定 綁定是指將程序調(diào)用與實(shí)際代碼相匹配。為了實(shí)現(xiàn)早期綁定,,先應(yīng)創(chuàng)建對(duì)對(duì)象庫(kù)的引用,。早期綁定可以在代碼中使用定義在對(duì)象庫(kù)中的常量,可以自動(dòng)列出對(duì)象的方法和屬性,,但早期綁定只有在所控制的對(duì)象擁有獨(dú)立的類型庫(kù)或?qū)ο髱?kù)文件才適用且還需要已安裝了特定的庫(kù),。而后期綁定則只是在運(yùn)行時(shí)才知道對(duì)象的類型并對(duì)對(duì)象進(jìn)行引用,因此不具備上述特點(diǎn),。 使用早期綁定創(chuàng)建對(duì)象通常更有效率,,使代碼能獲得更好的性能。因?yàn)閷?duì)象的早期綁定引用在編譯時(shí)可以通過(guò)VBE的解析,,而不是通過(guò)運(yùn)行時(shí)模塊解析,,因此早期綁定的性能要好得多。雖然在程序設(shè)計(jì)時(shí)不可能總是使用早期綁定,但應(yīng)該盡可能使用它,。 5,、關(guān)閉屏幕刷新 在Excel中,其ScreenUpdating屬性值的默認(rèn)值為True,,這樣當(dāng)寫數(shù)據(jù)到工作表或者執(zhí)行任何導(dǎo)致其顯示屬性變化的動(dòng)作時(shí),,Excel的屏幕界面將會(huì)不斷的刷新,不僅影響顯示,,而且影響程序運(yùn)行的速度,。您可以在進(jìn)入主程序運(yùn)行前將屏幕刷新屬性關(guān)閉,即用Application.ScreenUpdating = False語(yǔ)句關(guān)閉屏幕刷新,,這樣將大大改善程序的運(yùn)行速度,。 但在程序運(yùn)行完成前,要確保將其恢復(fù)為原來(lái)的設(shè)置,,即將ScreenUpdating屬性的值設(shè)置為True,。因?yàn)槟鷮?duì)該屬性的修改是永久性的修改,Excel不會(huì)為您自動(dòng)恢復(fù)其默認(rèn)值,,您必須用語(yǔ)句Application.ScreenUpdating = True恢復(fù)設(shè)置,。 6、設(shè)置計(jì)算模式為手動(dòng) 如果您的工作表中含有多個(gè)公式,,在每次單元格中的值發(fā)生變化時(shí),,公式都將會(huì)重新計(jì)算,這會(huì)影響程序運(yùn)行速度,。您可以在進(jìn)入主程序運(yùn)行前,,將計(jì)算模式設(shè)置為手動(dòng),即使用如下語(yǔ)句Application.Calculation = xlCalculationManual,,以避免不必要的計(jì)算,。 當(dāng)程序運(yùn)行結(jié)束前,您要恢復(fù)Excel的默認(rèn)計(jì)算模式設(shè)置,,即設(shè)置為自動(dòng)重算,,可使用下面的語(yǔ)句Application.Calculation = xlCalculationAutomatic,這同ScreenUpdating屬性一樣,,Excel不會(huì)自動(dòng)恢復(fù)其為默認(rèn)值,。Calculation屬性是對(duì)所有工作簿進(jìn)行的設(shè)置,您也可以用工作表的EnableCalculation屬性來(lái)設(shè)置對(duì)某個(gè)工作表是否進(jìn)行重新計(jì)算,。 7,、使用For Each…Next循環(huán) 可以使用For Each…Next循環(huán)來(lái)保證程序代碼更快地執(zhí)行。在使用For Each…Next循環(huán)時(shí),,對(duì)于存儲(chǔ)在集合或數(shù)組中的每個(gè)對(duì)象執(zhí)行一組語(yǔ)句,,程序更簡(jiǎn)潔,,也更容易閱讀、調(diào)試和維護(hù),。當(dāng)For Each…Next語(yǔ)句迭代集合時(shí),自動(dòng)指定一個(gè)對(duì)集合當(dāng)前成員的引用,,然后在到達(dá)集合的尾部時(shí)跳出循環(huán)語(yǔ)句,。 8、使用With…End With語(yǔ)句 可以使用With…End With語(yǔ)句來(lái)盡量減少對(duì)象引用,。使用With語(yǔ)句對(duì)指定的對(duì)象完成一系列的任務(wù),,而不用重復(fù)引用對(duì)象。也可以使用嵌套的With語(yǔ)句進(jìn)一步提高程序代碼的效率,。例如,,下面的使用With…End With語(yǔ)句是在同一個(gè)單元格中執(zhí)行多個(gè)操作。 With Workbooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1”) .Formula=”=SQRT(20)” With .Font .Name=”Arial” .Bold=True .Size=10 End With End With 同理,,可使用With…End With語(yǔ)句在同一個(gè)單元格區(qū)域中執(zhí)行多個(gè)操作,。 9、在執(zhí)行循環(huán)時(shí)考慮如何能夠盡可能地節(jié)省資源 (1)分析循環(huán)以查看是否正在不必要地執(zhí)行一些消耗內(nèi)存的重復(fù)操作,。例如,,是否可以在循環(huán)外(而不是在循環(huán)中)設(shè)置某些變量?每次都通過(guò)循環(huán)執(zhí)行的轉(zhuǎn)換過(guò)程是否可以在循環(huán)之外執(zhí)行,? (2)考慮是否必須在滿足特定的條件時(shí)才執(zhí)行循環(huán),。如果是,也許可以更早地退出循環(huán),。例如,,假設(shè)正在對(duì)一個(gè)不應(yīng)該包含數(shù)字字符的字符串進(jìn)行數(shù)據(jù)驗(yàn)證。如果循環(huán)要檢查字符串中的每個(gè)字符以確定其中是否包含數(shù)字字符,,那么您可以在找到第一個(gè)數(shù)字字符時(shí)立即退出循環(huán),。 (3)如果必須在循環(huán)中引用數(shù)組的元素,可以創(chuàng)建一個(gè)臨時(shí)變量存儲(chǔ)該元素的值,,而不是引用數(shù)組中的值,。從數(shù)組中檢索值比從相同類型的變量讀取值要慢。 10,、盡量減少OLE引用 可以通過(guò)盡量減少在VBA程序代碼中使用OLE(對(duì)象鏈接與嵌入自動(dòng)識(shí)別)引用來(lái)優(yōu)化程序代碼,。VBA語(yǔ)句中所調(diào)用的方法和屬性越多,執(zhí)行語(yǔ)句所用的時(shí)間就越多,。例如下面的兩個(gè)語(yǔ)句: 語(yǔ)句1:Workbooks(1).Sheets(1).Range(“A1”).Value=10 語(yǔ)句2:ActiveWindow.Left=200 執(zhí)行時(shí),,語(yǔ)句2比語(yǔ)句1快。 同樣,,上面所講的對(duì)重復(fù)使用的對(duì)象引用指定一個(gè)變量,,通過(guò)調(diào)用變量從而保證避免多次進(jìn)行對(duì)象引用,。 11、避免對(duì)象激活或者不需要先進(jìn)行先擇 在使用宏錄制器時(shí),,所生成的程序代碼在應(yīng)用任何方法或?qū)傩灾岸紩?huì)激活或者選擇對(duì)象,。但是,并不是在所有的情況下都需要這樣做,。所以,,在您編寫VBA程序代碼時(shí),不需要在對(duì)對(duì)象執(zhí)行任何任務(wù)之前都激活或者選擇每個(gè)對(duì)象,。 例如,,在Excel中,我們?nèi)绻沟谝恍凶兂纱煮w就必須先選項(xiàng)中它,。但在VBA中(除在圖表操作時(shí)需要選中圖表對(duì)象外),,很少需要這樣做,即VBA可以在不選中第一行的情況下,,將它變成粗體,。 宏錄制器的代碼: Rows("1:1").Select Selection.Font.Bold = True 改編后的代碼為: Row(“1:1”).Font.Bold=True 這樣做還可以使程序代碼更簡(jiǎn)潔,并且程序可以運(yùn)行得更快,。 12,、在一個(gè)語(yǔ)句中進(jìn)行復(fù)制或者粘貼 在用宏錄制代碼時(shí),首先是選擇一個(gè)區(qū)域,,然后再執(zhí)行ActiveSheet.Paste,。在使用Copy方法時(shí),可以在一個(gè)語(yǔ)句中指定復(fù)制的內(nèi)容及要復(fù)制到的目的地,。 例如,,將B5:C6區(qū)域的內(nèi)容復(fù)制到以單元格B8開(kāi)始的區(qū)域中,使用宏錄制器的代碼為: Range("B5:C6").Select Selection.Copy Range("B8").Select ActiveSheet.Paste 經(jīng)修改后的最佳代碼是: Range("B5:C6").Copy Destination:=Range("B8") 13,、盡可能少使用“.” 在前面已經(jīng)介紹過(guò)的對(duì)長(zhǎng)對(duì)象引用使用對(duì)象變量以及使用With…End With等都是簡(jiǎn)化”.”的方法,。因?yàn)樵诖a中的每個(gè)句點(diǎn)都表示至少一個(gè)(而且可能是多個(gè))過(guò)程調(diào)用,而這些過(guò)程調(diào)用必須在后臺(tái)執(zhí)行,。真正好的做法是在局部進(jìn)行緩存對(duì)象引用,,例如,應(yīng)該把對(duì)象模型中較高層次的對(duì)象引用保存到局部對(duì)象變量中,,然后用這些對(duì)象引用創(chuàng)建其他較低層次的對(duì)象引用,。例如,引用某單元格數(shù)據(jù)時(shí),,可用如下代碼: Dim i As Long For i=1 to 10 Workbooks(“Book1.xls”).Worksheets(“Sheet1”).Cells(1,i).Value=i Next i 但下面的代碼運(yùn)行效率更高,,因?yàn)榇a中引用Workbook對(duì)象和Worksheet對(duì)象的調(diào)用命令只執(zhí)行一次,而上面的代碼中卻要執(zhí)行10次,。 Dim ws As Worksheet Dim i As Long Set ws= Workbooks(“Book1.xls”).Worksheets(“Sheet1”) For i=1 to 10 ws.Cells(1,i).Value=i Next i 14,、合理地使用消息框和窗體 在一個(gè)很長(zhǎng)的程序中,,償試著將消息框或者窗體安排顯示在程序的最開(kāi)始或最后面,避免干擾用戶,。此外,,盡管窗體提供了許多功能,但它們能夠?qū)е挛募笮⊙杆僭黾?。還有就是盡量避免給工作表單元格鏈接用戶窗體控件,,因?yàn)檫@樣將會(huì)導(dǎo)致鏈接更新操作,影響程序運(yùn)行速度,。 15、盡可能加速對(duì)數(shù)字的運(yùn)算 (1)當(dāng)對(duì)整數(shù)進(jìn)行除法時(shí),,您可以使用整型除法運(yùn)算符(\)而不是浮點(diǎn)除法運(yùn)算符(/),,因?yàn)闊o(wú)論參與除法運(yùn)算的數(shù)值類型如何,浮點(diǎn)除法運(yùn)算符總會(huì)返回Double類型的值,。 (2)在任何具有整數(shù)值的算術(shù)表達(dá)式中使用Single或Double值時(shí),,整數(shù)均將被轉(zhuǎn)換成Single或Double值,最后的結(jié)果將是Single或Double值,。如果要對(duì)作為算術(shù)運(yùn)算結(jié)果的數(shù)字執(zhí)行多次操作,,可能需要明確地將該數(shù)字轉(zhuǎn)換為較小的數(shù)據(jù)類型。 16,、提高字符串操作的性能 (1)盡可能少使用連接操作,。可以在等號(hào)左邊使用Mid函數(shù)替換字符串中的字符,,而不是將它們連接在一起,。使用 Mid 函數(shù)的缺點(diǎn)是替換字符串必須與要替換的子字符串的長(zhǎng)度相同。例如,, Dim strText As String strText = "this is a test" Mid(strText, 11, 4) = "tent" (2)VBA提供許多可用來(lái)替換函數(shù)調(diào)用的內(nèi)部字符串常量,。例如,可以使用vbCrLf常量來(lái)表示字符串中的回車/換行組合,,而不是使用Chr(13) & Chr(10),。 (3)字符串比較操作的執(zhí)行速度很慢。有時(shí),,可以通過(guò)將字符串中的字符轉(zhuǎn)換為 ANSI 值來(lái)避免這些操作,。例如,下列代碼會(huì)檢查字符串中的第一個(gè)字符是否為空格: If Asc(strText) = 32 Then 上面的代碼會(huì)比以下代碼更快: If Left(strText, 1) = " " Then 17,、使用Asc()檢驗(yàn)ANSI的值 在VBA中,,可以使用Chr$()函數(shù)把數(shù)轉(zhuǎn)換成字符,并確定ANSI的值,,但是更好的是使用Asc()函數(shù)把字符串轉(zhuǎn)換成數(shù)值,,然后確定它的ANSI值,。如果需要進(jìn)行有限次數(shù)的這種檢驗(yàn),對(duì)程序代碼的效率可能不會(huì)產(chǎn)生很大影響,,但是,,如果需要在多個(gè)循環(huán)內(nèi)進(jìn)行這種檢驗(yàn)時(shí),這將節(jié)省處理時(shí)間并且有助于程序代碼更快地執(zhí)行,。 18,、使用Len()檢驗(yàn)空串 盡管有多種方法可檢驗(yàn)空串,但首選的是使用Len()函數(shù),。為了測(cè)試零長(zhǎng)度的串,,可以選擇把串與””相比較,或者比較串的長(zhǎng)度是否為0,,但這些方法比用Len()函數(shù)要用更多的執(zhí)行時(shí)間,。當(dāng)對(duì)字符串應(yīng)用Len()函數(shù)并且函數(shù)返回0值時(shí),說(shuō)明該字符串是空的或者是零長(zhǎng)度的字符串,。 并且,,因?yàn)樵贗f語(yǔ)句內(nèi)非零值被認(rèn)為是True,所以直接使用Len()函數(shù)而不必與””或0比較,,減少了處理時(shí)間,,因此執(zhí)行更快。 19,、有效地使用數(shù)組 用VBA數(shù)組而不是單元格區(qū)域來(lái)處理數(shù)據(jù),,即可以先將數(shù)據(jù)寫入到某個(gè)數(shù)組,然后用一個(gè)語(yǔ)句就可以將數(shù)組中的數(shù)據(jù)傳遞到單元格區(qū)域中,。 在創(chuàng)建已知元素的確定數(shù)組時(shí),,使用Array函數(shù)對(duì)于節(jié)約空間和時(shí)間以及寫出更具效率的代碼是非常理想的。例如,, Dim Names As Variant Names=Array(“Fan”,“Yang”,“Wu”,“Shen”) 此外,,應(yīng)該盡量使用固定大小的數(shù)組。如果確實(shí)選擇使用了動(dòng)態(tài)數(shù)組,,應(yīng)該避免數(shù)組每增加一個(gè)元素就改變一次數(shù)組的大小,,最好是每次增加一定數(shù)量的元素。 20,、使用Excel的內(nèi)置函數(shù) 對(duì)于要實(shí)現(xiàn)的某一功能,,如果有Excel的內(nèi)置函數(shù)能夠?qū)崿F(xiàn),那么就用Excel的內(nèi)置函數(shù),,不需要另外自定義函數(shù),,因?yàn)樽远x的函數(shù)總比Excel內(nèi)置的函數(shù)慢。
附件
- Ra8JtKDO.rar (9.37 KB)
-
2006-8-1 23:55, 下載次數(shù): 84
[原創(chuàng)]VBA編程問(wèn)答(第1輯)
- RDidpODM.rar (53.87 KB)
-
2006-8-1 23:56, 下載次數(shù): 79
[原創(chuàng)]VBA編程問(wèn)答(第1輯)
- WqtM1Z3M.rar (6.89 KB)
-
2006-8-1 23:57, 下載次數(shù): 34
[原創(chuàng)]VBA編程問(wèn)答(第1輯)
|
|
|
版主
- 積分
- 8009
- 財(cái)富
- 4733 ¥
- 技術(shù)
- 117
- 注冊(cè)時(shí)間
- 2003-3-19
- 總積分排名
- 55
|
2樓 大 中 小 發(fā)表于 2006-8-2 00:03 只看該作者
問(wèn)題2:如何禁用用戶窗體的關(guān)閉按鈕,? 解答:您可能不想用戶在單擊窗體右上角的X圖標(biāo)后關(guān)閉窗體,,您可以在用戶窗體代碼模塊中將UserForm_QueryClose過(guò)程的Cancel參數(shù)值設(shè)置為True,此時(shí)雖然X圖標(biāo)仍然存在,,但當(dāng)您單擊它時(shí)已不起作用,,因此可以防止用戶通過(guò)單擊該圖標(biāo)按鈕來(lái)關(guān)閉用戶窗體。例如,下面的示例提示用戶只能通過(guò)單擊用戶窗體上的“確定”按鈕來(lái)關(guān)閉該用戶窗體。您可以在VBE編輯器中插入一個(gè)用戶窗體,并在用戶窗體上放置一個(gè)名為“Ok”的按鈕,在用戶窗體代碼模塊中輸入下面的代碼進(jìn)行調(diào)試,。 ‘************************************************** Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) ‘CloseMode參數(shù)表明事件發(fā)生的原因 ‘若其值等于vbFormControlMenu則意味著用戶單擊了X圖標(biāo)按鈕 If CloseMode = vbFormControlMenu Then MsgBox "請(qǐng)單擊""確定""按鈕關(guān)閉本窗體" Cancel = True End If End Sub ‘************************************************** Private Sub Ok_Click() Unload UserForm1 End Sub =================================================================== 問(wèn)題3:可以撤銷宏所執(zhí)行的操作嗎? 解答:可以,但不能通過(guò)Excel內(nèi)置的功能自動(dòng)實(shí)現(xiàn)。您可以使用VBA代碼記錄下運(yùn)行宏程序前單元格或單元格區(qū)域原先的內(nèi)容,在“撤銷”命令中調(diào)用以恢復(fù)程序運(yùn)行前的狀態(tài),。 您可以使用Application對(duì)象的OnUndo方法作為宏程序結(jié)束前的最后一個(gè)代碼,,該方法允許您指定出現(xiàn)在“撤銷”菜單項(xiàng)中的文本以及點(diǎn)擊該文本后所運(yùn)行的過(guò)程。如下面的代碼所示: Application.Onundo “撤銷最后一個(gè)宏”,,”恢復(fù)宏程序” 為說(shuō)明上述方法,,下面列出了一個(gè)完整的示例。示例的完整代碼以及代碼說(shuō)明如下: ‘************************************************** Type RangeCellInfo '自定義類型存儲(chǔ)宏運(yùn)行所作出的改變 CellContent As Variant CellAddress As String End Type
Public OrgWB As Workbook Public OrgWS As Worksheet Public OrgCells() As RangeCellInfo ‘************************************************** Sub EditRange() ' 在所有被選取的單元格中插入X Dim i As Integer, cl As Range If TypeName(Selection) <> "Range" Then Exit Sub Application.ScreenUpdating = False ReDim OrgCells(Selection.Count) Set OrgWB = ActiveWorkbook Set OrgWS = ActiveSheet i = 1 ‘記錄下宏程序?qū)ぷ鞅碜鞒龈淖兦暗臓顟B(tài) For Each cl In Selection OrgCells(i).CellContent = cl.Formula OrgCells(i).CellAddress = cl.Address i = i + 1 Next cl ‘在所選單元格中填允X Selection.Formula = "X" ‘指定在“撤銷”菜單項(xiàng)中的文字及選擇該命令時(shí)所執(zhí)行的宏程序 Application.OnUndo "撤銷最后運(yùn)行的宏過(guò)程操作", "UndoEditRange" End Sub ‘************************************************** ‘恢復(fù)工作表原先的狀態(tài) Sub UndoEditRange() Dim i As Integer Application.ScreenUpdating = False On Error GoTo NoWBorWS OrgWB.Activate OrgWS.Activate On Error GoTo 0 '恢復(fù)宏運(yùn)行所作的改變 For i = 1 To UBound(OrgCells) Range(OrgCells(i).CellAddress).Formula = OrgCells(i).CellContent Next i Set OrgWB = Nothing Set OrgWS = Nothing Erase OrgCells NoWBorWS: End Sub 示例文檔見(jiàn)撤銷宏示例.xls,。 krV0Zt8k.rar (9.37 KB)
|
|
|
版主
- 積分
- 8009
- 財(cái)富
- 4733 ¥
- 技術(shù)
- 117
- 注冊(cè)時(shí)間
- 2003-3-19
- 總積分排名
- 55
|
3樓 大 中 小 發(fā)表于 2006-8-2 00:05 只看該作者
問(wèn)題4:如何將同一文件夾中的多個(gè)文本文件讀入到工作簿中,? 解答:通常,我們所看到的例子都是在工作簿中讀入一個(gè)文本文件中的內(nèi)容,。假設(shè)有幾個(gè)文本文件,,我們把它們放在與工作簿相同的文件夾中,那么,,現(xiàn)在如何在該工作簿中一次性讀取這幾個(gè)文本文件的內(nèi)容,。下面的程序演示了上述過(guò)程,示例工作簿附后,,其中源數(shù)據(jù)引用了 lichaobin網(wǎng)友在他的提問(wèn)貼中所附的數(shù)據(jù),。 分兩種情況: (一)所讀入的文本文件總行數(shù)小于65536行,,您可以使用以下代碼。 ‘************************************************** Sub Sample1() Dim n As Long, a(), ff As Integer, txt As String, myDir As String, x Dim myF As String, i As Long myDir = ThisWorkbook.Path & Application.PathSeparator myF = Dir(myDir & "*.txt") Do While myF <> "" ff = FreeFile Open myDir & myF For Input As #ff Do While Not EOF(ff) Line Input #ff, txt x = Split(txt, "|") n = n + 1 ReDim Preserve a(1 To n) a(n) = x Loop Close #ff myF = Dir() Loop Cells.Clear With ThisWorkbook.Worksheets("Sheet1").Range("a1") For i = 1 To UBound(a) .Offset(i - 1).Resize(, UBound(a(i)) + 1) = a(i) Next End With End Sub ‘************************************************** (二)所讀入的文本文件總行數(shù)大于65536行,,您可以使用以下代碼,。其中使用了一個(gè)變量t和一個(gè)判斷語(yǔ)句,當(dāng)多于65536行時(shí),,將剩下的數(shù)據(jù)寫入另一工作表中,。 Sub Sample2() Dim n As Long, a(), ff As Integer, txt As String, myDir As String, x Dim myF As String, i As Long, t As Integer t = 1 myDir = ThisWorkbook.Path & Application.PathSeparator myF = Dir(myDir & "*.txt") Do While myF <> "" ff = FreeFile Open myDir & myF For Input As #ff Do While Not EOF(ff) Line Input #ff, txt x = Split(txt, "|") n = n + 1 ReDim Preserve a(1 To n) a(n) = x If n = 65536 Then With ThisWorkbook.Sheets(t).Range("a1") For i = 1 To UBound(a) .Offset(i - 1).Resize(, UBound(a(i)) + 1) = a(i) Next End With n = 0: Erase a: t = t + 1 End If Loop Close #ff myF = Dir() Loop If n > 0 Then With ThisWorkbook.Sheets(t).Range("a1") For i = 1 To UBound(a) .Offset(i - 1).Resize(, UBound(a(i)) + 1) = a(i) Next End With End If End Sub 示例文檔見(jiàn)讀取多個(gè)文本文件.rar。 E27ouF6l.rar (53.87 KB)
|
|
|
版主
- 積分
- 8009
- 財(cái)富
- 4733 ¥
- 技術(shù)
- 117
- 注冊(cè)時(shí)間
- 2003-3-19
- 總積分排名
- 55
|
4樓 大 中 小 發(fā)表于 2006-8-2 00:07 只看該作者
問(wèn)題5:如何使用VBA刪除所有的空工作表,? 解答:可以分兩種情形來(lái)對(duì)待,。 (一)如果您想刪除同一工作簿中的所有空工作表,可以使用下面的兩個(gè)程序中的其中一個(gè): ‘************************************************** Sub test1() Dim ws As Worksheet Application.DisplayAlerts = False For Each ws In ActiveWorkbook.Worksheets ws.Activate If ActiveWorkbook.Worksheets.Count > 1 Then If IsEmpty(ActiveSheet.UsedRange) Then ws.Delete End If End If Next ws Application.DisplayAlerts = True End Sub ‘************************************************** Sub test2() Dim ws As Worksheet On Error GoTo Handdle Application.DisplayAlerts = False For Each ws In ActiveWorkbook.Worksheets ws.Activate With ws If Application.CountA(.Cells) = 0 Then .Delete End If End With Next ws Handdle: Application.DisplayAlerts = True End Sub (二)如果您想刪除已打開(kāi)的工作簿中的所有空工作表,,可使用下面的程序: ‘************************************************** Sub test() Dim ws As Worksheet Dim wb As Workbook Application.DisplayAlerts = False For Each wb In Workbooks wb.Activate For Each ws In ActiveWorkbook.Worksheets ws.Activate If ActiveWorkbook.Worksheets.Count > 1 Then If IsEmpty(ActiveSheet.UsedRange) Then ws.Delete End If End If Next ws Next wb Application.DisplayAlerts = True End Sub =================================================================== 問(wèn)題6:如何獲取計(jì)算機(jī)上可供使用的打印機(jī)列表,? 解答:您可能有時(shí)想獲取您的計(jì)算機(jī)上可供使用的打印機(jī)列表,然后從中選擇打印機(jī)輸出,。最簡(jiǎn)單的方法是,,您可以在代碼中添加下面的語(yǔ)句: Application.Dialogs(xlDialogPrint).Show =================================================================== 問(wèn)題7:如何基于某個(gè)單元格更新其它單元格的日期? 例如:我需要做的一個(gè)例行工作是依賴于兩個(gè)特定單元格的內(nèi)容添加一些日期到另一個(gè)單元格,。例如,,在單元格J2中有W(代表每周)或者B(代表Bi周)或者M(jìn)(代表每月),單元格N2中的內(nèi)容為一個(gè)可更新的日期,,如果J2中包含一個(gè)W我需要在單元格L2中添加7天,,或者如果J2中包含一個(gè)B我需要在單元格L2中添加14天,或者如果J2中包含一個(gè)M則在單元格L2中添加30天,,……在單元格J2中包含的信息W,B,或M決定計(jì)算的天數(shù),,單元格N2中包含原先約定的日期作為開(kāi)始計(jì)算的日期,單元格L2中的這個(gè)日期基于上面兩個(gè)單元格的日期更新,。 解答:可以粘貼下面的兩個(gè)程序之一到工作表代碼模塊中,。 (一)區(qū)分大小寫,您必須在工作表中輸入大寫的字母W,、B或M,。 ‘************************************************** Private Sub Worksheet_SelectionChange(ByVal Target As Range) If Range("J2").Text = "W" Then Range("L2") = Range("N2").Value + 7 ElseIf Range("J2").Text = "B" Then Range("L2") = Range("N2").Value + 14 ElseIf Range("J2").Text = "M" Then Range("L2") = Range("N2").Value + 30 End If End Sub (二)不區(qū)分大小寫,并使用了Select Case選擇語(yǔ)句。 ‘************************************************** Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address = "$N$2" Or Target.Address = "$J$2" Then Dim iDays As Byte Application.EnableEvents = False On Error GoTo ERRORHANDLER Select Case UCase(Range("J2").Value) Case "W" iDays = 7 Case "B" iDays = 14 Case "M" iDays = 30 End Select Range("L2").Value = Range("N2").Value + iDays Application.EnableEvents = True Exit Sub ERRORHANDLER: Application.EnableEvents = True End If End Sub =================================================================== 問(wèn)題8:如何編寫一個(gè)宏程序運(yùn)行另一個(gè)宏程序特定的次數(shù),? 解答:可以用一個(gè)簡(jiǎn)單的循環(huán)來(lái)實(shí)現(xiàn),。 ‘************************************************** Sub FirstMacro() Dim RunCount as Long Const RunMax As Long=10 ‘定義要運(yùn)行的次數(shù) For RunCount =1 To RunMax Call SecondMacro ‘調(diào)用要運(yùn)行的宏程序 Next End Sub =================================================================== 問(wèn)題9:如何在一個(gè)組合框中列出所有工作表中單元格D3中的值? 解答:假設(shè)用戶窗體中有一個(gè)名為ComboBox1的組合框,,您可在用戶窗體中添加以下代碼,,當(dāng)用戶窗體被激活時(shí),在組合框中將顯示出所有工作表中單元格D3的值,。 ‘************************************************** Private Sub UserForm_Activate() Dim ws As Worksheet For Each ws In Worksheets ComboBox1.AddItem ws.Range("D3").Text Next ws End Sub =================================================================== 問(wèn)題10:如何使工作表中的文本閃爍,? 解答:為了使文本閃爍,您需要周期性地執(zhí)行一個(gè)程序來(lái)變換文本的前景色,,OnTime方法可以用于周期性地運(yùn)行一個(gè)程序,。 ‘************************************************** Public RunWhen As Double Sub StartBlink() If Range("A1").Font.ColorIndex = 2 Then Range("A1").Font.ColorIndex = xlColorIndexAutomatic Else Range("A1").Font.ColorIndex = 2 End If RunWhen = Now + TimeSerial(0, 0, 1) Application.OnTime RunWhen, "StartBlink", , True End Sub ‘************************************************** Sub StopBlink() Range("A1").Font.ColorIndex = xlColorIndexAutomatic Application.OnTime RunWhen, "StartBlink", , False End Sub 在上面的這些程序中,您可以改變參數(shù)A1為您想要使文本閃爍的單元格或單元格區(qū)域,。在工作簿打開(kāi)時(shí),,您需要初始化這個(gè)程序,因此,,您可以放置下面的代碼到ThisWorkbook代碼模塊中,。 ‘************************************************** Private Sub Workbook_Open() StartBlink End Sub 當(dāng)工作簿關(guān)閉時(shí),您需要取消OnTime事件,,因此,,您需要放置下面的代碼到ThisWorkbook代碼模塊中。 ‘************************************************** Private Sub Workbook_BeforeClose(Cancel As Boolean) StopBlink End Sub 示例文檔見(jiàn)在Excel中閃爍文本.xls,。 HL3xux8P.rar (6.89 KB)
=================================================================== 問(wèn)題11:如何將工作簿中其它工作表名導(dǎo)入到指定的工作表中,? 解答:本問(wèn)題即將工作簿中除指定的工作表(如名為Name的工作表)外的其它的工作表名導(dǎo)入到指定的工作表中(即Name工作表中),。您可以使用下面的代碼,。 ‘************************************************** Sub Test() Dim ws As Worksheet Dim i As Long, j As Long Worksheets("Name").Range("A:A").Clear i = Worksheets("Name").Range("A65536").End(xlUp).Row For Each ws In Worksheets If ws.Name <> "Name" Then Worksheets("Name").Cells(i, 1) = ws.Name i = Worksheets("Name").Range("A65536").End(xlUp).Row + 1 End If Next ws End Sub =================================================================== 問(wèn)題12:如何在單元格中快速輸入帶秒的時(shí)間? 解答:一般,,在Excel中快速輸入日期和時(shí)間時(shí),,可使用快捷鍵,即按Ctrl+:組合鍵將快速在單元格中輸入當(dāng)前日期,,按Ctrl+Shift+:組合鍵將快速在單元格中輸入當(dāng)前時(shí)間,,但所顯示的時(shí)間為“小時(shí):分鐘”格式,不會(huì)顯示秒,。如果您想顯示“小時(shí):分鐘:秒”這樣的格式的話,,可以使用Onkey方法修改快捷鍵的缺省設(shè)置,如下所示,,運(yùn)行“設(shè)置快捷鍵”代碼即可,。 ‘************************************************** Sub 設(shè)置快捷鍵() Application.OnKey "+^:", "輸入時(shí)間" End Sub ‘************************************************** Sub 恢復(fù)快捷鍵() Application.OnKey "+^:" End Sub ‘************************************************** Sub 輸入時(shí)間() With ActiveCell .Value = Time() .NumberFormat = "hh:mm:ss" End With End Sub 如果您想恢復(fù)快捷鍵的缺省設(shè)置,運(yùn)行“恢復(fù)快捷鍵”過(guò)程,。
By fanjy in 2006-8-1
|
|