<output id="os3gq"><ruby id="os3gq"></ruby></output>

    1. <mark id="os3gq"></mark>
    2. VBA類模塊完全教程(下篇) -周芳
      Access軟件網QQ交流學習群(群號碼198465573),歡迎您的加入!
      首頁 >技術文章> Access數據庫-模塊/函數/VBA


      VBA類模塊完全教程(下篇)

      發表時間:2013/2/19 9:07:06 評論(2) 瀏覽(22717)  評論 | 加入收藏 | 復制
         
      摘 要:創建類屬性 創建類方法 創建類事件
      正 文:

      創建類屬性
            讓我們想一下作為類的使用者時,我們是如何操作對象的屬性的,對象屬性的操作不外乎讀和寫兩種。當我們要給對象的某個屬性賦值時,我們會:
      TextBox1.Text=”abc”
      當我們要讀取對象的屬性時,
      S= TextBox1.Text
      現在,看看作為類的提供者需要怎樣做。
      我們將“類1”改名為“MyClass”并為它創建一個名稱為x的字符型屬性。
      1.使用Public變量創建類屬性
      在類模塊中寫下行代碼:
      Public x$
      是的,就這么簡單,通常情況下,只需要這么簡單

       

      使用Property過程創建類屬性
      Private s$
      Public Property Get x() As String
        x = s
      End Property
      Public Property Let x(ByVal c As String)
        s = c
      End Property

            我們可以省去上面默認的Public。但看上去還是有點麻煩哦,不僅需要兩個公共過程,而且還要一個輔助的私有變量s和一個參數c。在類模塊中,Property過程把對屬性的讀寫分開了,說一下Property過程的工作機制,當標準模塊中的代碼讀取對象的屬性時,便會觸發存在的Property Get過程,或者說Property Get過程提供了屬性的讀功能,同樣,Property Let過程提供了寫屬性。這樣,上面的兩個過程(當然在模塊中沒有先后的要求),可以只有一個,或者雖然兩個都有,但卻不全是Public,從而提供出去的屬性是只讀或只寫(呵呵,沒見過只寫哈)。僅僅是為了提供只讀或只寫的屬性,代碼就從一行變成了七行?!這樣的理由,你不會信服, VBA中的類通常是提供給我們自己使用的!如果它確實是只讀的,我們自覺地去只讀就是了!我們使用Property過程還有其它理由,最基本的一條,我們可以利用這個“過程”來做我們想做的事??匆豢矗?

      Public Property Let x(ByVal c As String)
        s = Format(c, "0000")
      End Property

      這里我們只是簡單的利用了一下,更多的在后面你會看到。此外,誰會保證有一天你不使用VB給別人提供類呢,這個技術可是通用的。提供一段標準模塊的測試代碼,來看看我們上面構建的類屬性,你自己試試吧。

      Sub aTest()
        Dim mc As New MyClass
        mc.x = "123"
        Debug.Print mc.x
      End Sub

      就象我們給普通變量和對象變量賦值的方式不同一樣,對象變量是使用Set賦值的。對“對象”屬性,VBA提供了Property Set來代替構建“普通”屬性使用的Property Let。來看一段代碼:
       
      Private tx As Object
      Property Get x() As Object
        Set x = tx
      End Property
      Property Set x(ByVal o As Object)
        Set tx = o
      End Property
      和前面的比較一下,除了多一個Set,實在沒有什么不同。

      告訴你一個小秘訣,你可以按照Function去記住Property Get的用法,按照Sub去記住Property Let /Set

       

      屬性的初始值
            我們常常希望,當一個對象建立的時候,它的某些屬性會被自動賦予一個初始值,這樣,對具有最常見的屬性值的對象可以減少重復性的賦值工作。這需要借助于類的構建函數來完成。


            在類模塊代碼窗口的“通用”框中點擊向下的小三角箭頭,選擇“Class”,右面聲明框中可以看到兩個選項,“Initialize”和“Terminate”,我們對它們應該不陌生,很多對象都有這兩個事件,Initialize事件當對象建立時發生,Terminate事件在對象對釋放時發生。由于類是靜態存在的,它并不是真正的對象,所以在類模塊中,它們通常被稱為構建函數和析構函數,或構建過程和析構過程。對它們的理解和你在對象中的用法并沒有什么不同。當一個對象被建立時,構建函數將被首先執行,同樣,當對象釋放后,將執行析構函數。
       
      下面建立MyClass,屬性x初始值為”0001”的全部測試代碼:
      [類模塊MyClass的代碼]
      Option Explicit
      Private s$
      Public Property Get x() As String
        x = s
      End Property
      Public Property Let x(ByVal c As String)
        s = c
      End Property
      Private Sub Class_Initialize()
        s = "0001"
      End Sub
      [標準模塊1的代碼]
      Option Explicit
      Sub aTest()
        Dim mc As New MyClass
        Debug.Print mc.x
      End Sub
      隱者為你揭開了第一層面紗,你隱約已看到她美麗的面厐,雖然還不是很清晰,但你知道,早晚會的

       

      創建類方法
            放松一下,請拿出你家的紫砂壺,泡上一壺好茶,聽我給你將類的方法的故事,你的茶品完了,我的故事也差不多就講完了。
      1.構建類的方法其實就是在類模塊中寫公共的Sub和Function
      現在我們給前面提到的MyClass創建一個方法PutIntoActiveCell,功能是將x屬性值寫入活動單元格。
      Public x$
      Sub PutIntoActiveCell()
        ActiveCell = x
      End Sub
      在標準模塊中用下面的代碼測試一下:
      Sub aTest()
        Dim mc As New MyClass
        mc.x = "abc"
        mc.PutIntoActiveCell
      End Sub
      這是本回要告訴你的全部嗎?你還沒有開始品茶吧?就這樣了結束?這是最重要和基本的,但卻不是全部。
      你是否有一種感覺,但你不能清楚地說出來? 端起你可愛的茶杯,品一口茶,我們繼續。

       

      類的方法環境
            借用廣為眾知的一個名詞“數據環境”,雖然不準確,但我實在想不出更好的稱謂來代替,姑且這么叫吧。稍后你就會知道它的含義。


            類可以象VBA提供給我們的很多標準類一樣風光無限,所有的程序設計者都在工程中使用它,但更多時候,我們所構建的類只在特定的環境下被使用,類的方法環境是指包括類所在工程的其它成員在內的,可以調用的資源的集合。工作簿、工作表、窗體或其它,在類模塊中,你可以象在標準模塊中一樣操作它們,千萬不要因為換成了類模塊而產生任何疑慮,作為類的創建者,你要讓類模塊中的代碼象你在標準模塊中一樣親近它們,只要你認為必要。脫離了方法環境的、謹小慎微的、封閉的類實在沒有什么意義。如果你預期方法環境在運行時可能會有變化,你要事先預知它們并象在標準模塊中一樣使用恰當的措施,比如你不能確定運行時活動工作表的名稱(但你確定屆時會是一個工作表),你可以使用ActiveSheet。


            我反復說“和標準模塊一樣”,就是想告訴你在類模塊中創建方法時,對工程中其它成員的操作,和你已經熟悉的標準模塊中的方式的實在沒有什么不同,這一原則適用于類模塊中所有代碼(也許叫代碼環境更準確些),而不僅僅是構建方法的代碼。

            現在,你知道了,你剛才的感覺到的是開放的方法環境。是的,以后你會更深地體會到,作為好的提供者,開放的思維有多重要

      方法的兄弟—成員事件
            類方法的執行需要在代碼中以顯性的方式指定,象上面的mc.PutIntoActiveCell,有時候,當最終操作者觸發類對象成員(屬性)的某個事件,需要在事件發生時產生一系列的操作,這時,我們要運用成員事件。成員事件和方法都是類提供的一系列代碼的操作,倆兄弟的區別在于,成員事件無法也不必再由代碼顯性調用。
      我們來看一個具有普遍意義的事例。


      [重要例]
      窗體UserForm1上有5個CommandButton控件(名稱分別為默認CommandButton 1- CommandButton 5)和1個TextBox控件(名稱為TextBox1)。要求當各個CommandButton控件被點擊時,它的按鈕文字(Caption)會寫入TextBox1。
      如果不用類,我們需要為5個CommandButton控件分別寫5個相同的Click事件代碼。如:
      Private Sub CommandButton 1_Click()
        TextBox1 = CommandButton 1.Caption
      End Sub
      下面是用類的成員事件方法的代碼:
      ‘類模塊Cmds的代碼
      Option Explicit
      Public WithEvents cmd As CommandButton
      Private Sub cmd_Click()
        UserForm1.TextBox1 = cmd.Caption
      End Sub
      ‘窗體UserForm1的代碼
      Option Explicit
      Dim co As New Collection
      Private Sub UserForm_Initialize()
        Dim i%
        Dim myc As Cmds
        For i = 1 To 5
          Set myc = New Cmds
          Set myc.cmd = Me.Controls("CommandButton" & i)
          co.Add myc
        Next i
        Set myc = Nothing
      End Sub

       

            仔細玩味上例的每一行代碼,直至品完你壺中的茶。呵呵,因為它實在很有用。最后提一下Friend關鍵字,雖然在VBA中幾乎沒有什么用,但如果有一天你要制作ActiveX部件,可能會用到它。之所以要有Friend關鍵字,是因為類的私有部分在類模塊外是不可見的,但有時卻需要從外面訪問這些私有部分,這時,可以使用Friend關鍵字使屬性和方法成為“友元成員”。友元成員在本工程中相當于Public,但在工程外,它仍是Private 。


            隱者為你揭去了第二層面紗,你幾乎已看清她美麗的面龐,她帶著甜蜜的微笑,似乎在問:什么才是最美的期待?


      創建類事件
            在VBA中,因為我們既是提供者,也是使用者,所以通過良好地構建類的屬性和方法,已可以滿足我們需要全部的要求。我不再去解釋這個觀點,在本回后你自然會明白。從這個意義上講,創建類事件實在沒有必要。唯一的遺憾是,我們沒有體會到作為創建者的全部樂趣,標準類給我們提供了各種事件,當然希望自己也可以做到,想象中這應當是一件激動人心的事,所以,追求快樂是創建類事件的重要理由,另一個理由,前面已經提到。

       
            回到前面我們的MyClass類,我們將x屬性改名為Value屬性,雖然對屬性、方法以及事件的命名,VBA沒有特別的限制,但建議您不要象我前面那樣,隨便取一個x,可能的話,要盡量和標準類的成員(屬性、方法以及事件)名稱相一致。


            現在我們為“使用”者提供一個“Change”事件,不錯,我們給它取名為“Change”,而不再是隨意的“y”或其它(雖然也可以),這樣,我也不用解釋這個事件的用意了,呵呵。為了做到這一點,看看我們應該做什么。

       

      1.第一步:使用Event語句聲明事件
      看一下類模塊中現在的代碼:
      Option Explicit
      Public Event Change(ByRef Cancel As Boolean)
      Private s$
      Public Property Get Value() As String
        Value = s
      End Property
      Public Property Let Value(ByVal c As String)
        s = c
      End Property
      Private Sub Class_Initialize()
        s = "abc"  ‘初始值
      End Sub
      和前面的代碼比較,多出了一句:
      Public Event Change(ByRef Cancel As Boolean)

       

      這就是Event語句,只此一句,我們已經為我們的類聲明(我想使用“注冊”一詞是不是更妥切)了一個事件Change。在看Event語句產生的效果前,先來看它的特性:
      (1)為了聲明事件,Event總是Public的,這好理解吧。
      (2)事件可以不帶參數,如Public Event Change(),也可以帶參數,如我們上面給出的,但參數不能是命名參數,可選參數或數組參數。這里我只解釋一下命名參數的含義。我們知道,事件可以因特定的用戶事件而觸發,也可以在代碼中象方法一樣指定執行,如下面的CommandButton1_Click:
      Private Sub CommandButton2_Click()
        CommandButton1_Click
      End Sub
      但在調用對象的方法時我們通常喜歡這樣的方式:
      Selection.Sort Key1:=Range("A2"), order1:=xlAscending
      這里Key1、Order1就是命名參數,命名參數的好處是我們不必記住它們的次序,調用時直接以名稱和冒號后加等于號指定它的值,但對事件的調用卻不允許這樣。
      (3)事件沒有返回值。
       
      現在我們看一下,Event為我們做了什么。
      建立一窗體UserForm1,添加一個TextBox控件(名稱為TextBox1),兩個CommandButton控件(名稱為CommandButton1和CommandButton2),CommandButton1的Caption設置為“賦值”,CommandButton2的Caption設置為“讀值”,窗體的代碼如下:
      Option Explicit
      Dim WithEvents mc As MyClass
      Private Sub CommandButton1_Click()
        mc.Value = TextBox1 '賦值
      End Sub
      Private Sub CommandButton2_Click()
        MsgBox "mc當前的值為" & mc.Value '讀值
      End Sub
      Private Sub UserForm_Initialize()
        Set mc = New MyClass
      End Sub
          上面這段代碼實現的是,當點擊CommandButton1時便會將TextBox1的值賦給mc的Value,當點擊CommandButton2時便會顯示mc當前的Value值。
      來運行一下這個窗體,先點擊CommandButton2,此時顯示“abc”,是mc的初始值,然后在TextBox1輸入“123”,點擊CommandButton1,再點擊CommandButton2,顯示“123”,說明賦值成功了。
          呵呵,忘了,我們要做什么了!現在,請從UserForm1代碼窗口的“通用”框中選擇mc,哇!我們聲明的事件在右邊“聲明”框中已經出現了!
      此主題相關圖片如下:

      我們定義這個事件是希望當mc的值改變時響應的,現在就迫不及待地給它寫一句代碼吧:
      Private Sub mc_Change(ByRef Cancel As Boolean)
        If MsgBox("要改變mc的值嗎?", vbYesNo) = vbNo Then Cancel = True
      End Sub
          上面這句代碼你不會陌生吧,希望當用戶選擇了在改變時給用戶一個確認的機會。
      但是,現在點擊CommandButton1,卻不會給你選擇的機會,我們還有一步沒有做。
      第二步:使用RaiseEvent語句引發事件
      聲明了事件后,我們要做的,便是找到所有與事件發生關聯的地方,使用RaiseEvent語句引發事件,這里引發的含義相當于Call,就是調用用戶在事件中寫的代碼。在本例中,只有一個地方,就是Property Let Value過程中:
        Dim chyn As Boolean
        RaiseEvent Change(chyn)
        If chyn Then Exit Property
      通過傳遞回的chyn,決定是否執行后面的賦值語句。下面就是添加了RaiseEvents語句后的類模塊的代碼:
      Option Explicit
      Public Event Change(ByRef Cancel As Boolean)
      Private s$
      Public Property Get Value() As String
        Value = s
      End Property
      Public Property Let Value(ByVal c As String)
        Dim chyn As Boolean
        RaiseEvent Change(chyn)
        If chyn Then Exit Property
        s = c
      End Property
      Private Sub Class_Initialize()
        s = "abc"
      End Sub
      現在你可以去運行你的窗體了,我們要的效果應該是達到了吧。為了便于你調試,下面給出窗體的全部代碼:
      Option Explicit
      Dim WithEvents mc As MyClass
      Private Sub CommandButton1_Click()
        mc.Value = TextBox1 '賦值
      End Sub
      Private Sub CommandButton2_Click()
        MsgBox "mc當前的值為" & mc.Value '讀值
      End Sub
      Private Sub UserForm_Initialize()
        Set mc = New MyClass
      End Sub
      Private Sub mc_Change(ByRef Cancel As Boolean)
        If MsgBox("要改變mc的值嗎?", vbYesNo) = vbNo Then Cancel = True
      End Sub

       

          當然,我們可以把上面mc_Change的代碼要做的直接在Property Let Value過程的代碼中,從而不使用事件。這就是在本回的開頭說的。

       
            事件的構建已經完成,說了這么多,其實你只要記住兩步的標題就可以了。到這里,關于VBA類最基本最重要的部分已經給朋友們介紹完了。余下的,留著您在未來的探索路上慢慢體會吧,也請您不要忘了和大家分享您的喜悅。
      隱者已向你展示了她所有的秘密,鉛華去盡,只有美麗

       


      Access軟件網交流QQ群(群號:198465573)
       
       相關文章
      一個演示VBA類和繼承例子  【朱亦文  2009/10/19】
      VBA類模塊完全教程(上篇)   【周芳(轉)  2013/2/5】
      VBA類模塊完全教程(中篇)   【周芳(轉)  2013/2/11】
       
       訪客評論
      2019/3/20Susan
      通俗易懂,好文

      2013/2/20sosopain
      可惜沒有繼承,,,失去了類真正的魅力

      總記錄:2篇  頁次:1/1 9 1 :
       
       發表評論
      評論內容 (必填)

      常見問答
      技術分類
      相關資源
      文章搜索
      關于作者

      周芳

      文章分類

      文章存檔

      友情鏈接
       
         
      湖北11选5