2010-02-20 127 views
2

無論如何,我可以在一個函數內爲單元賦值/名稱嗎?VBA爲函數內的單元賦值?

謝謝

編輯

對不起不夠明確,這裏是我的要求。

我有一個用戶定義的函數(= MyFunction()),它可以從Excel工作表中調用。因此,我還有一個菜單按鈕,當用戶單擊按鈕時,我需要調用所有調用= MyFunction()的函數。

我的計劃是在MyFunction()中,爲調用單元指定一個名稱rerefence並將其存儲在vba中。所以我可以有一個單元格名稱數組。然後,當點擊菜單按鈕時,我可以調用這些單元格引用。

請幫我實現這一點。有沒有更好的方法來保持單元格引用?

+0

這與http://stackoverflow.com/questions/2259035/how-to-get-address-of-cell-which-calls-a-vba-functions-in-a-excel-愚弄的人表 – 2010-02-21 03:42:23

+0

不,我需要知道如何爲函數的調用單元賦一個名稱,而不是如何從調用單元對象中檢索值 – nimo 2010-02-21 03:53:21

+0

啊,現在它更清晰了。看到答案。 – GSerg 2010-02-21 11:46:17

回答

1

編輯:

啊,現在我明白了。 最簡單的方法是僞造一個參數:MyFunction(ByVal r As Variant),並且,無論何時在工作表上使用此函數,都應提供與參數完全相同的單元格:=MyFunction(A1)。當單擊菜單項時,將A1中的值更改爲任何內容,並且所有MyFunctions都將重新計算。

或者,您可以在函數的主體中使用Application.Volatile。這樣,每次打開的工作簿中的任何單元格發生更改時,都會重新計算。

可能也使用模塊級別的集合來存儲引用,但Excel有時只是重置項目,從而丟失模塊級別的變量。如果你足夠勇敢嘗試:

Option Explicit 

Private RefsToCalculate As New Collection 

Public Function MyFunction() As Long 
    Static i As Long 

    i = i + 1 
    MyFunction = i 

    If TypeOf Application.Caller Is Excel.Range Then 
    On Error Resume Next 
    RefsToCalculate.Add Application.Caller, Application.Caller.Address 
    On Error GoTo 0 
    End If 
End Function 

Public Sub MenuButtonClicked() 
    Dim i As Long 

    For i = 1 To RefsToCalculate.Count 
    RefsToCalculate(i).Dirty 
    Next 
End Sub 
+0

我需要的是爲函數調用單元格設置一個名稱,然後當用戶單擊菜單項(當用戶單擊菜單項時,我需要重新評估單元格中的函數調用)時,可以引用此單元格。任何想法如何做到這一點? – nimo 2010-02-20 18:47:59

+0

這很不清楚。請編輯你的問題,並舉一個很好的例子。 – GSerg 2010-02-20 20:30:38

0

「我有一個用戶自定義函數(= MyFunction的()),它可以從一個Excel工作表被稱爲因此,我也有一個菜單按鈕在哪裏。當用戶單擊按鈕時,需要調用所有調用= MyFunction()的函數。「

這可以輕鬆完成,無需創建緩存來存儲一系列單元格。但是,您需要注意計算方法。我相信下面的代碼可以確保你的範圍總是被計算出來,但是:(1)如果calc方法不是手動的,那麼Excel最終控制什麼是計算的,什麼時候和爲什麼,因此它可能重新計算其他單元格。 (2)同樣,我相信它保證用你的函數重新計算所有的單元格而不管計算方法如何,但是我沒有測試下面的表格和半自動計算方法的代碼。

下面的代碼提供兩種方法:

(1) - 重新計算包含公式的所有單元:的優點是,跳過一個循環,並在其中的代碼,缺點是,你可能迫使許多的重新計算比你真正需要更多的細胞。 (2) - 建立一個範圍的興趣和重新計算範圍:缺點是建立該範圍可能需要一些嚴重的計算工作。優點是,如果calc方法設置爲manual,那麼我相信Excel將只重新計算該範圍內的單元格。

我猜這個選擇取決於你需要解決的問題的具體細節。 「我的計劃是在MyFunction()中,爲調用單元分配一個名稱rerefence並將其存儲在vba中,因此我可以有一個單元格名稱數組,然後當菜單按鈕被點擊。「

如果你真的想要遵循這種方法,或者如果你確實需要爲你描述的目的創建一個單元格緩存,那麼這可以完成,儘管它是基本的,但它甚至可以以這樣的方式構建:它在Excel會話之間保留。但是,這需要更多的工作,更高級的方法,而且還是相當簡陋的。國際海事組織,這個問題明顯矯枉過正。更糟糕的是,每次單元更新時都必須調用代碼,以確保緩存保持最新,這可能會對性能造成很大影響。至於GSerg的建議:這種方法 - 正如他自己所說的 - 並不能真正控制緩存本身的生命。這就是說,每次到達緩存時,您都必須檢查Excel是否已將其擦除,如果是這種情況,請重新構建它。

結論:我建議你不要緩存單元格。相反,我建議您嘗試按需求查找需要重新計算的單元格,並強制重新計算您可以找到的最佳方式。仍然不相信?在這種情況下,使用Application.Caller.Address(請參閱下面的代碼)來檢索調用您的函數的單元格的地址。備註:在Excel 2003中實施和測試。包含用於格式化的C#樣式註釋符號。

Option Explicit 

Public Sub ReEvaluateMyFunction() 

    On Error GoTo Handle_Exception 

    Dim targetCells As Range 
    Dim targetCell As Range 
    Dim rangeToRecalc As Range 

    /*'Workbook and worksheet names 
    'hard-coded for the example*/ 

    Set targetCells = Application _ 
    .Workbooks("Book1") _ 
    .Worksheets("Sheet1").UsedRange _ 
    .SpecialCells(xlCellTypeFormulas) 

    If targetCells Is Nothing Then Exit Sub 

    /*'You can narrow down the range if you know 
    'more about the function's return type, e.g.: 

    '.SpecialCells(xlCellTypeFormulas, xlNumbers) 
    '.SpecialCells(xlCellTypeFormulas, xlTextValues) 

    'OPTION 1: re-calculate all cells in the range 

    'Remark: unless calc method is set to "Manual", which 
    'should give you full control, I think there's no 
    'guarantee that other cells will not be recalculated*/ 

    If Application.Calculation = xlCalculationManual Then 
     //'Use to force recalculation if calc mode is manual 
     targetCells.Calculate 
    Else 
     //'Use this to force recalculation in other cases 
     targetCells.Dirty 
    End If 

    Set targetCells = Nothing 
    Exit Sub 

    /*'OPTION 2: create a range specific to your 
    'function and recalculate that range*/ 

    For Each targetCell In targetCells 

     If targetCell.Formula = "=MyFunction()" Then 

      If rangeToRecalc Is Nothing Then 
       Set rangeToRecalc = targetCell 
      Else 
       Set rangeToRecalc = Union(rangeToRecalc, targetCell) 
      End If 

     End If 

    Next targetCell 

    //'Same comments as before 
    If Application.Calculation = xlCalculationManual Then 
     rangeToRecalc.Calculate 
    Else 
     rangeToRecalc.Dirty 
    End If 

    Set rangeToRecalc = Nothing 
    Set targetCell = Nothing 
    Set targetCells = Nothing 

    Exit Sub 

Handle_Exception: 

    Set rangeToRecalc = Nothing 
    Set targetCell = Nothing 
    Set targetCells = Nothing 

    MsgBox "An error has been found: " + Err.Description, vbCritical 

End Sub 

Public Function MyFunction() As String 

    MyFunction = Application.Caller.Address 

End Function