【发布时间】:2015-12-14 15:55:23
【问题描述】:
我有一个 Excel 工作簿,需要允许用户撤消工作表中的多项更改。我在每个我能想到的论坛上都在网上搜索过,但一直没有找到答案。我意识到在运行宏时,excel 中的撤消问题存在问题,并且能够使用派生自 here 的代码来处理此问题。
这是我目前的流程:
-
创建全局变量以保存工作簿的初始状态和更改。代码如下:
Private Type SaveRange Val As Variant Addr As String End Type Private OldWorkbook As Workbook Private OldSheet As Worksheet Private OldSelection() As SaveRange Private OldSelectionCount As Integer Private InitialState() As SaveRange Private InitialStateCount As Integer -
通过构建一个包含 Workbook_Open 子中所有单元格的值的数组 (InitialState) 来获取工作簿的初始状态。代码如下:
Private Sub Workbook_Open() GetInitialCellState End Sub Private Sub GetInitialCellState() Dim i As Integer, j As Integer, count As Integer Dim cellVal As String Dim sampID As Range, cell As Range Dim e1664 As Workbook Dim rawData As Worksheet Dim table As Range Dim LastRow As Integer, LastCol As Integer LastRow = Worksheets("Raw_Data").Range("A65536").End(xlUp).Row LastCol = Worksheets("Raw_Data").UsedRange.Columns.count Set e1664 = ThisWorkbook Set rawData = e1664.Sheets("Raw_Data") Set sampID = rawData.Range("SAMPLEID").Offset(1) Set table = rawData.Range(sampID, "R" & LastRow) i = 0 j = 0 count = 0 ReDim InitialState(i) For i = 0 To (LastRow - sampID.Row) For j = 0 To LastCol ReDim Preserve InitialState(count) InitialState(count).Addr = sampID.Offset(i, j).address InitialState(count).Val = sampID.Offset(i, j).Value count = count + 1 Next j Next i InitialStateCount = count - 1 End Sub -
在单元格中输入值时,将输入的值存储到另一个数组 (OldSelection) 中,该数组保存输入的值。这是在 Workbook_Change 子中完成的。这里的重要部分是 Call SaveState(OldSelectionCount, Target.Cells.address, Target.Cells.Value) 和 Application.OnUndo "Undo the last action", "GI.OR.E1664 .20150915_DRAFT.xlt!Sheet1.RevertState" 件,如下面的数字 4 和 5 所示。代码如下:
Private Sub Worksheet_Change(ByVal Target As Range) Dim cell As Range, InWtRange As Boolean Dim y As Integer, x As Integer, count As Integer Dim LastRow As Integer 'This saves the changed values of the cells Call SaveState(OldSelectionCount, Target.Cells.address, Target.Cells.Value) try: y = Me.Range("SampleID").Row If Target.Column > 5 And Target.Column < 8 Then If Range("A" & Target.Row).Value = Range("A" & Target.Row + 1).Value Then If Range("A" & Target.Row + 1).Value <> "" Then Range(Target.address).Offset(1).Value = Range(Target.address).Value End If End If Else 'If initial pan weight add start date If Target.Column = 8 Then If Target.Cells.Text <> "" Then If Not IsNumeric(Target.Cells.Value) Then GoTo Finally Else Application.EnableEvents = False Range("StartDate").Offset(Target.Cells.Row - y).Value = Format(Now(), "MM/DD/YY HH:NN:SS") Application.EnableEvents = True End If Else Application.EnableEvents = False Range("StartDate").Offset(Target.Cells.Row - y).Value = "" Application.EnableEvents = True End If End If End If LastRow = Worksheets("Raw_Data").Range("A65536").End(xlUp).Row For Each cell In Target.Cells 'Debug.Print Target.Cells.Address If cell.Value <> "" Then If Not IsNumeric(cell.Value) Then GoTo Finally Select Case cell.Column Case 9, 11, 13 Application.EnableEvents = False If CalcHEM(cell.Row - y, cell.Column) Then End If Application.EnableEvents = True Case Else 'Do nothing yet End Select 'Cells(Target.Row + 1, Target.Column).Select End If Next 'This will allow the changed values to be undone Application.OnUndo "Undo the last action", "GI.OR.E1664.20150915_DRAFT.xlt!Sheet1.RevertState" Finally: If Application.EnableEvents = False Then Application.EnableEvents = True Exit Sub Catch: MsgBox "An error has occurred in the code execution." & vbNewLine _ & "The message text of the error is: " & Error(Err), vbInformation, "TSSCalcs.AddQC" Resume Finally End Sub -
SaveState Sub 将保存添加到 OldSelection 数组中的任何已更改的值。代码如下:
Private Sub SaveState(count As Integer, Addr As String, Val As Double) Dim i As Integer Dim cell As Range If TypeName(Selection) <> "Range" Or Selection.count > 1 Then Exit Sub ReDim Preserve OldSelection(count) Set OldWorkbook = ActiveWorkbook Set OldSheet = ActiveSheet For Each cell In Selection OldSelection(count).Addr = Addr OldSelection(count).Val = Val Next cell OldSelectionCount = OldSelectionCount + 1 End Sub -
RevertState Sub 只会撤消最后一个操作!我不能允许撤消最后一个条目。代码如下:
Private Sub RevertState() Dim i As Integer, index As Integer Dim prevItem As SaveRange Dim address As String OldWorkbook.Activate OldSheet.Activate Application.EnableEvents = False address = OldSelection(OldSelectionCount - 1).Addr OldSelectionCount = OldSelectionCount - 2 If OldSelectionCount <= 0 Then ReDim OldSelection(0) For i = 0 To InitialStateCount If InitialState(i).Addr = address Then prevItem.Val = InitialState(i).Val index = i End If Next i Range(InitialState(index).Addr).Formula = prevItem.Val Else ReDim Preserve OldSelection(OldSelectionCount) For i = 0 To OldSelectionCount If OldSelection(i).Addr = address Then prevItem.Val = OldSelection(i).Val index = i End If Next i 'OldSelectionCount = OldSelectionCount + 1 Range(OldSelection(index).Addr).Formula = prevItem.Val End If OldSelectionCount = OldSelectionCount + 1 Application.EnableEvents = True End Sub
有谁知道允许多次撤消的方法吗?
任何解决此问题的帮助将不胜感激!
【问题讨论】:
-
过去曾研究过类似的问题(不是在 Excel 中),其想法是创建一种堆栈结构来保存一系列状态,而不是只保存一个状态。跨度>
-
您可能会发现这篇文章和示例对您的项目很有趣。创建撤消处理程序以撤消 Excel VBAjkp-ads.com/Articles/UndoWithVBA00.asp> 所做的更改和撤消处理程序示例 jkp-ads.com/downloadscript.asp?filename=UndoHandler.zip>
-
您发给我的两个链接都失效了,但是包含您所指信息的链接应该是here。虽然这是很好的信息,但代码需要的调试比它的价值要多。真正的问题在于 onUndo 方法。如果可能的话,我想使用微软的,但我自己写可能更容易。如果我找到解决方案,我会发布它。
-
您解决了吗?
-
请参阅下面关于我如何解决此问题的答案。