在概述页面中显示上次更新的行 - Excel

时间:2013-02-01 23:28:54

标签: excel list vba rows auto-update

我在excel中有一个共享工作簿,其中包含多个工作表和一个名为overview的主要工作表。

e.g。概述 - Sheet1 - Sheet2 - Sheet 3

在1/2/3表格中,我或其他人用一些数据更新行。

很难跟踪工作簿中的最后一个条目(因为我需要搜索所有工作表),所以我想创建一个"前10"我的概述页面中的动态列表,它将自动更新工作簿中最后10个更新的行。

有人可以帮我吗?

以下是一个例子:enter image description here

谢谢!

1 个答案:

答案 0 :(得分:4)

最干净的解决方案是:

在工作簿级别添加事件处理程序以捕获正在更改的单元格;在处理程序中,执行以下操作:

  • 关闭事件处理(您将更改工作表,不想进入无限循环)!
  • 关闭屏幕更新
  • 在前面的第1行
  • 上插入一行
  • 在此处输入已更改行的副本
  • 添加更改用户和日期/时间的用户(如果您愿意)
  • 返回原始选择
  • 开启屏幕更新
  • 启用事件处理

以下是逐步说明(示例文件可以从http://www.floris.us/SO/download/XLexample.xlsm下载) - 假设PC上有Excel 2010。其他版本的差异很小......

  1. 确保您的文件保存为.xlsm格式 - 这告诉Excel有宏
  2. 在添加所有这些内容之前创建该文件的备份 - 以防万一你搞砸了!
  3. 关闭所有其他文件(暂时) - 请参阅前面的评论
  4. 确保您的文件有四个工作表:“摘要”,“窗口小部件”,“事物”和“东西”(或者您认为有用的任何名称 - 我将通过这些名称引用它们,而不是“Sheet1”等。)
  5. 右键单击“窗口小部件”的选项卡,然后选择“查看代码”
  6. 将以下代码粘贴到工作表的“代码”窗口中:
  7. Private Sub Worksheet_Change(ByBal Target as Range)
      On Error GoTo procErr
      process_change Target
      Exit Sub
    
    procErr:
      MsgBox "Got an error: " & Err.Description
      Err.Clear
      Application.EnableEvents = True
    End Sub`
    
    1. 对每个“数据”工作表重复上述步骤:“东西”和“东西”(但不是“摘要”)
    2. 当Visual Basic编辑器打开时(您完成所有粘贴的操作),使用Insert-> Module
    3. 在工作簿中插入新的代码模块
    4. 将以下代码粘贴到您创建的模块中:
    5. Option Explicit
      
      Sub process_change(ByVal Target As Range)
      ' when a cell is changed on one of the worksheets, this function is called
      ' it copies the most recently changed row
      ' and inserts it on the second line of the "summary" worksheet
      ' right below the headers
      ' if the headers include "changed by" and/or "last changed" (exactly)
      ' then that column will be updated with the (windows) user name and date, respectively
      ' similarly, if a column named "source" exists, it will contain the address of the row
      ' (sheet name / row number). In that case, if there was an earlier occurrence of the same row
      ' (multiple edits), the earlier occurence is removed
      ' you may use this code as is - but there is no warranty as to its useability
      
      Dim s1 As Worksheet, s2 As Worksheet
      Dim srcAddress As String
      Dim oldSelection As Range
      
      ' don't update screen during processing - prevent "flickering"
      Application.ScreenUpdating = False ' set to True when debugging
      
      ' don't accept events until we're done
      Application.EnableEvents = False
      
      ' store old selection
      Set oldSelection = Selection
      
      Dim ri As Integer           ' index of changed row
      Dim rowAddress As String
      ri = Target.Row
      rowAddress = ri & ":" & ri  ' address of changed row
      
      if ri = 1 Then
        Application.EnableEvents = True
        Exit Sub                  ' don't record changes to the headers
      End If
      
      Range(rowAddress).Select
      Selection.Copy              ' copy changed row
      
      Set s1 = ActiveSheet        ' know where we will go back to
      srcAddress = s1.Name & ":row" & ri ' full address to be used later
      
      Set s2 = ActiveWorkbook.Sheets("summary")
      
      s2.Range("2:2").Insert      ' add a row at the top of the list
      s2.Select                   ' activate sheet where we want to paste
      Range("A2").Select          ' leftmost cell of column
      ActiveSheet.Paste           ' paste the entire changed row
      
      ' optionally, we can add "source", "last changed" and "changed by"
      ' we do this if appropriately named columns exist
      ' slightly clumsy code to catch errors...
      Dim lcCol
      If Not IsError(Application.Match("last changed", Range("1:1"), 0)) Then
        lcCol = Application.Match("last changed", Range("1:1"), 0)
        Range("A2").Offset(0, lcCol - 1).Value = Date
      End If
      
      Dim cbCol
      If Not IsError(Application.Match("changed by", Range("1:1"), 0)) Then
        cbCol = Application.Match("changed by", Range("1:1"), 0)
        Range("A2").Offset(0, cbCol - 1).Value = UserName
      End If
      
      Dim srcCol
      If Not IsError(Application.Match("source", Range("1:1"), 0)) Then
        srcCol = Application.Match("source", Range("1:1"), 0)
        ' find earlier entry regarding this row...
        Columns("A:A").Offset(0, srcCol - 1).Select
        Dim sf As Range
        Set sf = Selection.Find(What:=srcAddress, After:=ActiveCell, LookIn:= _
              xlFormulas, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:= _
              xlNext, MatchCase:=False, SearchFormat:=False)
        If Not sf Is Nothing Then
        ri = sf.Row
        rowAddress = ri & ":" & ri  ' address of changed row
        Range(rowAddress).Select
        Selection.Delete
        End If
        Range("A2").Offset(0, srcCol - 1).Value = srcAddress
      End If
      
      s1.Activate                     ' go back to original worksheet
      Application.CutCopyMode = False ' get rid of the "marching ants"
      oldSelection.Select             ' select the previous selection "like nothing happened"
      
      ' and turn on screenupdating and events...
      Application.EnableEvents = True
      Application.ScreenUpdating = True
      
      End Sub
      
      Sub eventsOn()
      Application.EnableEvents = True
      End Sub
      
      Public Function UserName()
      ' note - this function only works on PC
        UserName = Environ$("UserName")
      End Function
      

      完成所有这些操作后,您现在可以将标题放在工作表中 - 在所有四个工作表中使用相同的列标题。在第一个(摘要)表中,您可以选择添加三个标题:这些标题不应与您使用的其他标题相同,并且可以调用(确切地说 - 没有多余的空格,大小写......):sourcelast changedchanged by

      如果最后三个列标题不存在,则行为如下:

      每次对三个工作表中的一个进行更改时,进行更改的行将被复制到摘要表的第一行,位于标题下方。其他一切都会向下移动一行。

      如果添加“source”列,则会发生两件事:源(表单名称:行号)将添加到该列中,并且将删除该相同源(同一行)的所有先前条目。因此,您只能看到给定行的“最新更改”。

      如果添加“更改者”,您将获得进行最后更改的用户的名称; “最后更改”标题将包含上次更改的日期。

      如果你能从这里弄清楚,请告诉我 - 如果你遇到问题,请使用我上面链接的示例电子表格来指导你。