簡體   English   中英

如何通過VBA獲取/設置Excel中單元格的唯一ID

[英]How to get/set unique id for cell in Excel via VBA

我希望為Excel數據表中的每個數據行設置/定義一個唯一的ID - 這樣我可以在向前傳遞數據時使用它,並且當在其上面添加/刪除行時它保持不變。

我的想法是使用Range的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的那些限制之一,但如果我從帶狀按鈕觸發的代碼中嘗試它,我也會得到同樣的錯誤...

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

編輯:正如Ant想的那樣,我保護了表單,但即使在未鎖定的單元格中,它仍然會失敗。 取消保護工作表修復了問題....但我使用了“保護UserInterFaceOnly:= True”這應該允許我這樣做。 如果我在保護工作表時手動允許“編輯對象”它也可以工作,但我沒有看到編程選項 - 我需要調用AutoOpen中的Protect功能來啟用UserInterfaceOnly功能...

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

提前致謝。 克里斯

好的...

看起來如果工作表被鎖定,宏就沒有對ID等低級信息的寫訪問權。

但是,我認為不可能在UDF中取消保護表單。 根據設計,UDF受到嚴格限制; 我認為使用細胞配方控制片材保護會破壞細胞配方僅影響細胞的配方范例。 有關詳細信息,請參閱Microsoft網站上的此頁面

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

  • 放棄保護
  • 放棄UDF,使用Worksheet_Change事件捕獲單元格更改並在那里寫入ID
  • 使用UDF將ID寫入單元格值,而不是保存到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計數器(至少在您的示例中提供的有限詳細信息下)。

希望這可以幫助。

與Ant一致 - 您的代碼在Excel 2003 SP3上運行正常。

我也能用:

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

啊哈! 我想我擁有它。

我認為你是從一個數組公式中調用它,它只被稱為ONCE的全范圍。 您無法獲取范圍的ID - 只有一個單元格。 這解釋了為什么Application.Caller.ID失敗,因為Range(“A1:B9”)。ID生成Application-defined or object-defined error

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

我想我們可能會遇到一些問題,但我認為他們正在測試問題,而不是代碼本身的問題。 首先,如果從Cell以外的任何其他函數調用該函數,如立即窗口,其他代碼等,將不會設置Application.Caller。 這就是生成對象未找到錯誤的原因。 其次,如果您復制/粘貼具有該功能的單元格,您也可以復制/粘貼該ID。 因此無論您將其粘貼到何處,輸出都將保持不變。 但是,如果你只是復制文本(而不是單元格),然后粘貼然后這將工作正常。 (包括您對Application.Caller的原始使用。)

問題出在Application.Caller上。

由於您是從用戶定義的函數調用它,它將向您傳遞錯誤說明。 以下是幫助文件中的注釋。

備注

此屬性返回有關如何調用Visual Basic的信息,如下表所示。

來電者 - 返回值

  • 在單個單元格中輸入的自定義函數 - 指定該單元格的Range對象
  • 自定義函數,它是一系列單元格中數組公式的一部分 - 指定該單元格范圍的Range對象
  • Auto_Open,Auto_Close,Auto_Activate或Auto_Deactivate宏 - 文檔的名稱為文本
  • 由OnDoubleClick或OnEntry屬性設置的宏 - 宏應用的圖表對象標識符或單元格引用(如果適用)的名稱
  • 宏對話框(工具菜單),或上面未描述的任何調用者 - #REF! 錯誤值

由於您是從用戶定義的函數調用它,所以正在發生的事情是Application.Caller將錯誤代碼的String返回到您的范圍變量curCell。 它不會導致錯誤處理程序拾取的錯誤。 之后會發生什么,你引用了curCell,它實際上不再是一個范圍了。 在我的機器上,它嘗試設置curCell = Range(“Error 2023”)。 無論該對象是什么,它可能不再具有ID屬性,當您嘗試設置它時,它會拋出該對象錯誤。

這是我會嘗試的...

  1. 嘗試刪除錯誤處理程序,看看VBA是否會拋出Range(Application.Caller.Address)上的任何異常。 這不會解決它,但它可以指向正確的方向。

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

  3. 嘗試使用Option Explicit。 這可能會使你設置curCell的行拋出一個錯誤,因為Range(Application.Caller.Address)看起來不像是傳回一個范圍,這是curCell的數據類型。

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

感謝您的幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM