2009-06-19 318 views
5

我想爲我的Excel數據表中的每個數據行都定義一個唯一的ID--這樣我可以在向前傳遞數據時使用它,當行被添加/刪除時相同。如何通過VBA在Excel中獲取/設置單元格的唯一ID

我的想法是使用範圍的ID屬性(msdn link

所以,我有一個用戶自定義函數(UDF),我該得到的每一行中放置/套的ID如下:

Dim gNextUniqueId As Integer 

Public Function rbGetId(ticker As String) 
    On Error GoTo rbGetId_Error 
    Dim currCell As Range 
    'tried using Application.Caller direct, but gives same error 
    Set currCell = Range(Application.Caller.Address) 
    If currCell.id = "" Then 
     gNextUniqueId = gNextUniqueId + 1 
     'this line fails no matter what value I set it to. 
     currCell.id = Str(gNextUniqueId) 
    End If 
    rbGetId = ticker & currCell.id 
    Exit Function 

    rbGetId_Error: 
    rbGetId = "!ERROR:" & Err.Description 
End Function 

但這未能以與

「應用程序定義或對象定義的錯誤」

提到的線

我想也許它的UDF的侷限之一,但我也得到了同樣的錯誤,如果我嘗試從代碼從功能區按鈕觸發...

如何保持一致的IDS沒有其他的建議 - 也許我應該通過我的功能區按鈕填充單元格,找到沒有ID的單元格並生成/設置單元格值...

編輯: 由於Ant認爲,我保護了表格,但即使在未鎖定的單元格中,仍然失敗。取消保護工作表可以解決問題....但我已經使用了「保護UserInterFaceOnly:= True」,這應該允許我這樣做。如果我在保護工作表時手動允許「編輯對象」,它也可以工作,但我沒有看到編程選項 - 我需要在AutoOpen中調用保護功能以啓用UserInterfaceOnly功能...

我想我需要關閉/保護我的ID設置 - 假設可以在UDF中完成......它似乎不能,因爲這不起作用 - 既沒有ActiveSheet.unprotect也沒有ActiveWorkbook.unprotect :(

在此先感謝 克里斯

+1

你的代碼工作正常,在與此在Excel 2003和2007中的書沒有被鎖定或類似的東西? – Ant 2009-06-19 11:28:00

回答

0

我發現如果使用「Protect DrawingObjects:= False」保護工作表,UDF可以設置Id。奇怪。

感謝所有與此幫助。

1

同意螞蟻 - 你的代碼工作正常,這裏的Excel 2003 SP3

。 0

我也可以使用:

Set currCell = Application.Caller 
If Application.Caller.ID = "" Then 
    gNextUniqueId = gNextUniqueId + 1 
    'this line fails no matter what value I set it to. 
    currCell.ID = Str(gNextUniqueId) 
End If 

啊哈!我想我已經擁有了。

我想你是從一個數組公式中調用它,並且它只被稱爲一次全範圍。您無法獲取範圍的ID - 只有一個單元格。這解釋了爲什麼Application.Caller.ID不適合您,因爲Range(「A1:B9」).ID生成一個Application-defined or object-defined error

當您使用Range(Application.Caller.Address)獲取「單元格」時,只需將此錯誤推遲到currCell.ID行。

+0

它不是一個範圍公式,只是一個單元格。 – 2009-06-19 14:00:32

+0

以上您的編輯 - 您是否嘗試過使用ActiveSheet.Unprotect或ActiveWorkbook.Unprotect?如果你想避免明確表單(明智之舉),你可以隨時引用Cell.Parent。我認爲,因爲UDF是用戶界面的一部分,作爲一個公式,它已被阻止對錶單進行任何更改,但這只是一種預感。 – 2009-06-19 14:18:22

1

我想我們可能會遇到一些問題,但我認爲他們正在測試問題,而不是代碼本身的問題。首先,如果您使用Cell以外的任何其他方法調用該函數,如直接窗口,其他代碼等,則不會設置Application.Caller。這就是生成你的對象找不到的錯誤。其次,如果你複製/粘貼具有該功能的單元格,他們也可以通過複製/粘貼該ID。所以無論你粘貼到哪裏,輸出都會保持不變。但如果你只是複製文本(而不是單元格),然後粘貼,那麼這將工作正常。 (包括你原來使用的Application.Caller。)

+0

感謝您的ID的複製/粘貼功能 – 2009-06-20 07:48:16

4

好了...

它不會出現,如果表被鎖定,宏不必低級別信息的寫入權限,如ID。

但是,我不認爲有可能取消UDF中的工作表。按照設計,UDF受到嚴格限制;我認爲使用單元格公式控制表單保護會打破單元格公式隻影響單元格的公式範例。 有關更多詳細信息,請參閱Microsoft網站上的this page

我認爲這限制了您的選擇。你必須:

  • 放棄工作表保護
  • 放棄UDF,使用Worksheet_Change事件來捕獲細胞的變化和寫入ID有
  • 使用寫ID進入細胞值的UDF,而不是保存到ID

當您嘗試使用專門用於計算單元格的東西以在工作表上創建永久標記時,UDF方法充滿了問題。

儘管如此,下面是一個UDF示例,您可以使用它將「永久」值加蓋到單元格上,該單元格可以在受保護工作表的未鎖定單元格上工作。這個只適用於單個單元格(儘管它可以適用於數組公式)。

Public Function CellMark() 

    Dim currCell As Range 
    Set currCell = Range(Application.Caller.Address) 

    Dim myId As String 
    ' must be text; using .value will cause the formula to be called again 
    ' and create a circular reference 
    myId = currCell.Text 

    If (Trim(myId) = "" Or Trim(myId) = "0") Then 
     myId = "ID-" & Format(CStr(gNextUniqueId), "00000") 
     gNextUniqueId = gNextUniqueId + 1 
    End If 

    CellMark = myId 

End Function 

雖然這是相當有缺陷的。但是,使用複製或填充框將保留先前複製的值。只有明確地將單元格設置爲新的公式才能起作用。但是,如果您再次將公式輸入到單元格中(只需單擊它,按ENTER鍵)就會計算一個新值 - 這是標準單元格行爲。

我認爲Worksheet_Change事件是要走的路,它有更多的緯度。下面是一個簡單的例子,用於更新任何單元格更改的ID。它可以根據您的特定情況量身定製。此功能需要添加到每個工作表上需要ID設置行爲。

Private Sub Worksheet_Change(ByVal Target As Range) 

    Dim currCell As Range 
    Set currCell = Target.Cells(1, 1) 

    Dim currId As String 
    currId = currCell.ID 

    If Trim(currCell.ID) = "" Then 
     Target.Parent.Unprotect 
     currCell.ID = CStr(gNextUniqueId) 
     Target.Parent.Protect 
     gNextUniqueId = gNextUniqueId + 1 
    End If 

End Sub 

最後一張紙條;在所有情況下,如果您重新打開工作表(至少在您示例中提供的有限的詳細信息下),您的ID計數器將被重置。

希望這會有所幫助。

1

問題出在Application.Caller上。

由於您是從用戶定義函數調用它,它會傳遞給您一個錯誤描述。這是幫助文件中的註釋。

備註

此屬性返回有關基本是如何視覺叫,如圖所示,下表中的信息。

來電 - 返回值

  • 在單個小區中輸入定製功能 - Range對象指定單元
  • 自定義功能是在一個範圍內單元的陣列式的一部分 - A範圍對象指定單元格範圍
  • 一種Auto_Open,AUTO_CLOSE,Auto_Activate,或Auto_Deactivate宏 - 圖表對象標識符或單元的名稱 - 該文件爲文本
  • 宏由任一OnDoubleClick或OnEntry屬性設置的名稱參考, NCE(如果適用)的宏適用
  • 宏對話框(工具菜單),以上沒有描述任何來電者 - 該#REF!誤差值

因爲你是從用戶定義的函數調用它,所發生的事情是Application.Caller將返回錯誤代碼的String你的範圍變數curCell。它不會導致你的錯誤處理程序會收到錯誤。之後會發生什麼是你參考curCell,它實際上不再是一個範圍。在我的機器上,它嘗試設置curCell = Range(「Error 2023」)。無論這個對象是什麼,它可能不再有一個ID屬性,當你嘗試設置它時,它會拋出你的對象錯誤。

這裏就是我會嘗試...

  1. 嘗試刪除您的錯誤處理程序,看看VBA拋出了對範圍(Application.Caller.Address)任何異常。這不會解決它,但它可以指出你在正確的方向。

  2. 無論是通過邏輯或Application.ActiveCell或者無論你想這樣做,直接引用的單元格。例如Range(「A1」)或Cells(1,1)。 Application.Caller.Address似乎不是一個很好的選擇。

  3. 嘗試使用顯式的選項。由於Range(Application.Caller.Address)看起來並不像它傳遞一個返回的範圍(這是curCell的數據類型),所以這可能會使你設置curCell的那一行拋出一個錯誤。

相關問題