[英]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方法充滿了問題,因為您正在嘗試使用專門用於計算單元格的東西來在工作表上創建永久性標記。
盡管如此,這是一個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的信息,如下表所示。
來電者 - 返回值
由於您是從用戶定義的函數調用它,所以正在發生的事情是Application.Caller將錯誤代碼的String返回到您的范圍變量curCell。 它不會導致錯誤處理程序拾取的錯誤。 之后會發生什么,你引用了curCell,它實際上不再是一個范圍了。 在我的機器上,它嘗試設置curCell = Range(“Error 2023”)。 無論該對象是什么,它可能不再具有ID屬性,當您嘗試設置它時,它會拋出該對象錯誤。
這是我會嘗試的...
嘗試刪除錯誤處理程序,看看VBA是否會拋出Range(Application.Caller.Address)上的任何異常。 這不會解決它,但它可以指向正確的方向。
無論是通過邏輯還是Application.ActiveCell,或者您想要這樣做,直接引用單元格。 例如Range(“A1”)或Cells(1,1)。 Application.Caller.Address似乎不是一個很好的選擇。
嘗試使用Option Explicit。 這可能會使你設置curCell的行拋出一個錯誤,因為Range(Application.Caller.Address)看起來不像是傳回一個范圍,這是curCell的數據類型。
我發現如果用“Protect DrawingObjects:= False”保護工作表,UDF可以設置Id。 奇怪。
感謝您的幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.