有效的方法来select和复制到最后一行数据

上下文
我在Excel中build立了一个模型,允许用户从付费系统下载预算和支付数据。 用户可以加载一个成本中心预算(在I_Budget表单中)进行调整,按保存,数据被转储到“SavedData”表单中。 然后他们可以将另一个成本中心加载到I_Budget中。

但是,如果用户犯了错误,或者希望在SavedData中修改之前编辑的预算,则可以在I_Budget中单击“加载”,数据将被复制。

VBA代码
从SavedData加载用户预算的代码:

Public Sub LoadUsersSavedBudgets() Const WORKSHEET_DATA = "SavedData" Const WORKSHEET_BUDGET = "I_Budget" Const START_CELL = "A2" Const END_COLUMN = "H" ' Check if the user can perform the load action If IsEmpty(Sheets(WORKSHEET_DATA).Range("A2").Value) Then Exit Sub Worksheets(WORKSHEET_BUDGET).Unprotect ' A fudge to make Excel copy the data in the sheet Worksheets(WORKSHEET_DATA).Visible = True ' Select all rows in the selection Call DynamicColumnSelector(WORKSHEET_DATA, START_CELL, END_COLUMN) ' Set the range of the selected cells Set Rng = Application.Selection ' Copy the selection Rng.Copy ' Now paste the results With Sheets(WORKSHEET_BUDGET).Range("A18") .PasteSpecial xlPasteValues .PasteSpecial xlPasteFormats End With Worksheets(WORKSHEET_BUDGET).Protect ' Clear the data in I_Budget to give the user a blank canvas Call DeleteUsersSavedBudgets Worksheets(WORKSHEET_DATA).Visible = False Application.ScreenUpdating = True Sheets(WORKSHEET_BUDGET).Select MsgBox "Success! Your budgets have been loaded." End Sub 

将用户预算保存到SavedData中的代码:

 Public Sub SaveUsersBudgetAdjustments() Const WORKSHEET_BUDGET = "I_Budget" Const START_CELL = "A18" Const END_COLUMN = "H" Const WORKSHEET_OUTPUT = "SavedData" Const FILTER_COST_CENTRE = "I_Setup!I16" Dim nRng As Range ' Protect user from running this method if no data has been laoded If IsEmpty(Range("I_Budget!H18").Value) = True Then Exit Sub ' Issue warning to user If MsgBox("Would you like so save your changes into the O_Budget sheet?" & vbNewLine & vbNewLine & "You can always load them again for editing.", vbYesNo) = vbNo Then Exit Sub Application.ScreenUpdating = False ' We make sure the budget adjustments have been taken into account before any saving begins Call UpdateRevisedBudget Worksheets(WORKSHEET_BUDGET).Unprotect ' Select all rows in the selection Call DynamicColumnSelector(WORKSHEET_BUDGET, START_CELL, END_COLUMN) ' Set the range of the selected cells Set Rng = Application.Selection ' Delete the destination contents 'Sheets(WORKSHEET_OUTPUT).Rows("2:" & Rows.Count).Clear ' Copy and paste the selection into the destination sheet Rng.Copy ' A fudge to allow the copying and pasting of data to work If IsEmpty(Sheets(WORKSHEET_OUTPUT).Range("A2").Value) Then With Sheets(WORKSHEET_OUTPUT).Range("A2") .PasteSpecial xlPasteValues End With Else With Sheets(WORKSHEET_OUTPUT).Range("A1").End(xlDown).Rows.Offset(1, 0) .PasteSpecial xlPasteValues End With End If ' and clear the selection contents Selection.ClearContents Worksheets(WORKSHEET_BUDGET).Protect Application.ScreenUpdating = True End Sub 

也许最感兴趣的是我调用dynamicselect数据到最后一行的方法:

 Private Sub DynamicColumnSelector(shtValue, StartCellValue, StartColumnValue) 'Best used when column length is static Dim sht As Worksheet Dim LastRow As Long Dim StartCell As Range Set sht = Worksheets(shtValue) Set StartCell = Range(StartCellValue) 'Refresh UsedRange Worksheets(shtValue).UsedRange 'Find Last Row LastRow = sht.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row 'Select Range Sheets(shtValue).Select sht.Range(StartCellValue & ":" & StartColumnValue & LastRow).Select End Sub 

考试问题
我的问题是,虽然上述的工作,它感觉臭和低效率。 有没有更好的方法,我可以在工作表中select数据并复制它? 我必须考虑到SavedData表中的最后一行,因为我们可能会不断向其添加数据。

find最后一行数应该这样工作(这不是真的更短,只是一点点简单):

  sht.Cells.SpecialCells(xlCellTypeLastCell).Row 

在你的情况下,这应该产生与sht.Cells.Find相同的结果,因为你之前访问过UsedRange 。 但是,即使您之前不访问UsedRangeFind操作也应该提供最后一个非空行,而SpecialCells解决scheme可能会返回实际上较大的行号,因为用户在那里填充了一些值,删除了值并且未保存之前的文件。

此外,我会避免调用一个子select一个范围,然后由Application.Selection由下一个函数抓取。 更好的DynamicColumnSelector是使DynamicColumnSelector成为一个函数,返回关注的Range

  Function DynamicColumnSelector(...) as Range ' ... Set DynamicColumnSelector=sht.Range(...) End Function 

并像这样称呼它

  Set Rng = DynamicColumnSelector(...) Rng.Copy 

这使得您的代码在以后的更改中更加健壮。 更改或依赖于全局select的代码在以后需要更改执行顺序或在其间插入一些附加代码时,容易出错。 更糟的是,它更长,更慢,对用户有视觉效果。 直接传递范围对象的代码没有这些问题。

不幸的是, PasteSpecial操作只能与剪贴板一起使用,而不能直接用于范围到范围的拷贝。 如果你要复制值,你不需要PasteSpecial ,但是如果你想复制格式为wll,这可能是最简单和最安全的解决scheme。 所以我不希望有一个比你自己find的更简单的复制/粘贴解决scheme。

正如你所问:只复制没有任何格式的值,没有剪贴板:

 Set rng = DynamicColumnSelector(...) Set destinationRng = Sheets(WORKSHEET_OUTPUT).Range("A2") rng.Copy destinationRng 

可以。