2013-04-11 79 views
9

下面是我自己回答的一個問題,但是它對我造成了很大的挫折,我在網上搜索它時遇到了很多麻煩,所以我在節省一些時間&努力爲別人,也許我自己的希望在這裏發帖,如果我在未來忘記這一點:

對於VBA(在我的情況,MS Excel)中,該Public聲明應該把這些變量(或函數)可以被該模塊中的其他函數或子例程以及任何其他模塊全局訪問。

原來,這是不正確的,在Forms
的情況下,我懷疑還在Sheets,但我沒有驗證後者。

總之,以下將不會創建一個公共的,可訪問的變量Form創建時,因此會崩潰,說bYesNo和DRATE變量mModule1是不確定的:
公共變量在VBA中並不是真正公開的

(inside fMyForm) 
Public bYesNo As Boolean` 
Public dRate As Double 

Private Sub SetVals() 
    bYesNo = Me.cbShouldIHaveADrink.value 
    dRate = CDec(Me.tbHowManyPerHour.value) 
End Sub 
(Presume the textbox & checkbox are defined in the form) 

(inside mModule1) 
Private Sub PrintVals() 
    Debug.Print CStr(bYesNo) 
    Debug.Print CStr(dRate) 
End Sub 


但是,如果你讓下面的輕微變化,這一切都將正常工作:

(inside fMyForm) 

Private Sub SetVals() 
    bYesNo = Me.cbShouldIHaveADrink.value 
    dRate = CDec(Me.tbHowManyPerHour.value) 
End Sub 
(Presume the textbox & checkbox are defined in the form) 

(inside mModule1) 
Public bYesNo As Boolean` 
Public dRate As Double 
Private Sub PrintVals() 
    Debug.Print CStr(bYesNo) 
    Debug.Print CStr(dRate) 
End Sub 


mModule1將工作完全正常,並假設fMyForm總是先調用,然後由PrintVals程序運行時,從形式的文本框和複選框值將適當地捕獲。



老實說,我不可能理解MS在這個變化中想的是什麼,但是缺乏一致性是對效率的極大厭倦,像這些學習的特質,這些記錄如此糟糕,以至於2013年的谷歌搜索中有可能已經存在了十年或更長時間對於搜索來說如此具有挑戰性。

+3

Userform和Sheet模塊是對象模塊:它們的行爲與常規模塊的行爲不同。但是,您可以使用類似於引用類屬性的方式引用用戶窗體中的變量。在你的例子中提到'fMyForm.bYesNo'就能正常工作。如果您沒有將bYesNo聲明爲Public,則它將不可用於表單之外的代碼,因此,當您將其設置爲Public時,它確實與非Public不同。 – 2013-04-11 21:39:43

+3

這是一個衆所周知的事實,如果你想要真正的公共變量,你需要在代碼模塊中聲明它們,而不是在Form/Sheet代碼區域。請參閱此鏈接http://msdn.microsoft.com/en-us/library/office/gg264241.aspx公共變量可用於項目中的任何過程。如果公共變量是在標準模塊或類模塊中聲明的,那麼它也可以用於任何聲明公共變量的項目中的項目。' – 2013-04-11 21:40:34

+0

關於你最後的評論'哪些記錄很差,以至於Google搜索在2013年,對於可能已經存在十年或更長時間的內容來說,搜索非常具有挑戰性。「也許您正在使用錯誤的關鍵字進行搜索?嘗試在Google中搜索? 'msdn VBA聲明公共變量';) – 2013-04-11 21:51:14

回答

2

首評:

用戶窗體和表模塊是對象模塊:他們不循規蹈矩的方式作爲常規模塊相同。但是,您可以使用類似於引用類屬性的方式引用用戶窗體中的變量。在你的例子中提到fMyForm.bYesNo會正常工作。如果您沒有將bYesNo聲明爲Public,則它將不可用於表單之外的代碼,因此,當您將其設置爲Public時,它確實與非Public不同。蒂姆 - 威廉姆斯4月11日在'13 21:39

實際上是一個正確的答案...

+1

請將此答案標記爲「社區答案」 – 2015-11-30 15:11:00

0

作爲一個快速的附加答案社區的答案,只是擡頭:

在實例化表單時,可以使用表單對象本身,也可以使用New並將其放入一個變量中來創建表單對象的新實例。後一種方法是更清潔的IMO,因爲這使得使用更少單一化。

但是,在您的用戶表單中您呼叫卸載(Me)時,所有公共成員都將被擦除乾淨。所以,如果你的代碼是這樣的:

Dim oForm as frmWhatever 
    Set oForm = New frmWhatever 
    Call oForm.Show(vbModal) 
    If Not oForm.bCancelled Then ' <- poof - bCancelled is wiped clean at this point 

我用它來防止這種情況的解決方案,它是爲OP一個很好的替代解決方案,以及被捕獲所有IO與形式(即所有公共成員)分成一個單獨的類,並使用該類的一個實例與表單進行通信。所以,例如

Dim oFormResult As CWhateverResult 
    Set oFormResult = New CWhateverResult 
    Dim oForm as frmWhatever 
    Set oForm = New frmWhatever 
    Call oForm.Initialize(oFormResult) 
    Call oForm.Show(vbModal) 
    If Not oFormResult.bCancelled Then ' <- safe