查找Excel工作簿的工作表名称和行号

时间:2011-12-02 18:37:50

标签: excel vba excel-vba excel-2007

我正在使用包含三个数据工作表的工作簿。每个工作表都有一个合同编号列。必须排除某些合同并在单独的工作表中注明。

我想创建Excel VBA宏:

  1. 提示用户输入要排除的特定合同号
  2. 存储合约编号
  3. 在所有三个工作表的合同列中搜索合同编号
  4. 在已经创建的“摘要”工作表中注明不需要的合同详细信息
  5. 完全删除不需要的合约行
  6. 对于用户输入的'n'个合同,宏应循环执行此过程。

    Public contString As String
    Public x As Variant
    Public xCount As Variant
    
    Sub find()
    contString = InputBox(Prompt:="Enter contract numbers to exclude(Comma Delimited).      Cancel to include all contracts.", _
          Title:="Exclude Contracts", Default:="1715478")
      x = Split(contString, ",")
      xCount = UBound(x) 'Number of contracts entered by user
    End Sub
    
    Sub SearchWS1()
    Sheets("WS1").Activate
    Columns("I:I").Select 'Contract Number Column
    Selection.find(What:=x(i), After:=ActiveCell, LookIn:=xlValues, _
        LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
        MatchCase:=False, SearchFormat:=False).Activate
    BKWS = ActiveCell.Worksheet.Name
    BKRow = ActiveCell.Row
    If BKRow > 0 Then
       Cname = Range("G" & BKRow)
       Cnumber = Range("I" & BKRow)
       Cvalue = Range("K" & BKRow)
       'Summarize Excluded Contract Info on Summary WS
       Range("Summary!B25").Value = "Exclusions:"
       Range("Summary!B26").Value = Cnumber
       Range("Summary!C26").Value = Cname
       Range("Summary!D26").Value = Cvalue
       'Select and Delete Contract
       Rows(ActiveCell.Row).Select
       Rows(BKRow).EntireRow.Delete
    Else
       Call SearchWS2 'SearchWS2 is essentially the same as SearchWS1 and Calls SearchWS3 if contract isn't found. 
    End If
    End Sub
    

    如果第一个WS中不存在合同号,我会收到“对象变量或未设置块”之类的错误。一旦我可以修复此错误,我将需要通过循环为用户输入的每个合同号运行此过程。任何有关调试错误或为此设置循环的帮助将非常感激。

    谢谢!

2 个答案:

答案 0 :(得分:3)

  1. 使用InputBox输入合约编号(例如,逗号分隔)。使用Split函数拆分结果。
  2. 将合约号码存储在您隐藏的单独工作表中(wks.visible=xlVeryHidden,其中wksworksheet个对象)。
  3. 使用多维数组查找值以存储值。
  4. 使用rFound=saArray打印2D数组到找到的工作表(其中rFoundrange对象,saArray是2D数组。
  5. 大量使用录制宏来学习语法。

    有关检索和打印到cells的快速方法,请参阅this example

    <强>更新

    对不起,这很邋but但是我把它扔到了一起,很明显,它还没有经过测试。希望这可以帮助。对不起,我也不应该让你使用这样的高级技术,但我很难回去。

    dim j as integer, k as integer, m as long, iContractColumn as integer
    Dim x() as string, saResults() as string
    dim vData as variant
    dim wks(0 to 2) as worksheet
    
    iContractColumn=????
    
    set wks(0) = Worksheets("First")
    set wks(1) = Worksheets("Second")
    set wks(2) = Worksheets("Third")
    
    redim saresults(1 to 100, 1 to 2)
    m=0
    'Loop thru worksheets
    for j=0 to 2
      'Get data from worksheet
      vdata=wks(j).range(wks(j) _
        .cells(1,iContractColumn),wks(j).cells(rows.count,iContractColumn).end(xlup))
      'Loop through data
      for k=1 to ubound(vdata)
        'Loop through user criteria
        For i = 0 To UBound(x)
          'Compare user criteria to data
          if x(i)=cstr(vdata(k,1)) then
            'Capture the row and worksheet name
            m=m+1
            'If array is too small increase size
            if m>ubound(saresults) then 
              redim preserve saresults(1 to ubound(saresults)*2, 1 to 2)
            end if
            'Get name and row.
            saresults(m,1)=wks(j).name
            saresults(m, 2)=k
            exit for
          end if
        next i
      next k
    next j
    
    'Resize array to correct size
    redim preserve saresults(1 to m, 1 to 2)
    'Print results to a result page (you could also create hyperlinks here
    'that would make it so the person can click and go to the respective page.
    'You would have to do a loop for each result on the range.
    with worksheets("Result Page")
      .range(.cells(1,1),.cells(m,2))=saresults
    end with
    

答案 1 :(得分:2)

我几乎无法添加Jon49的答案,这似乎涵盖了基础知识。但我希望我在VBA编程生涯中早些时候发现过Forms。它们起初可能有点令人困惑,但是一旦掌握了它们,它们就会极大地增加宏的可用性。

表单可用于从用户(而不是InputBox)获取值,也可用于向用户提供进度信息。我只会谈谈第二种用法。你的宏可能需要一些时间;用户有时间喝一杯咖啡还是会在5秒内完成?我讨厌坐在那里的节目说“请等待 - 这可能需要几分钟到几个小时”。

以下代码将表单加载到内存中,将其显示给用户并在结尾处将其从内存中删除。如果您没有卸载表单,它将在宏结束后保留​​在屏幕上,如果您想为用户留言,这可能很有用。此表单显示为“无模式”,表示宏显示并继续。如果显示为“模态”,则宏将停止,直到用户输入表单所需的任何信息为止。

  Load frmProgress
  Progress.Show vbModeless
  ' Main code of macro
  Unload frmProgress

提供表格教程的网站没有尽头,所以我将主要描述的是什么而不是如何。

在VB编辑器中,插入一个UserForm。如果你想要它更大,拖动底部和右边缘。使用“属性”窗口将名称更改为frmProgress。

从工具箱中拖出四个标签并将它们排成一行。将标签1的标题设置为“工作表”,将标签3的标题设置为“of”。名称标签2“lblWSNumCrnt”和名称标签4“lblWSNumTotal”。

在“for j = 0 to 2”

周围添加以下内容
frmProgress.lblWSNumTotal.Caption = 3
for j = 0 to 2
  frmProgress.lblWSNumCrnt.Caption = j + 1
  DoEvents

这意味着用户将看到以下内容,并且当宏投射时,n从1步进到3步:

Worksheet    n  of     3

为行号添加另外四个标签,以及围绕k循环的以下代码:

frmProgress.lblRowNumTotal.Caption = ubound(vdata, 1)
for k = 1 to ubound(vdata, 1)
  frmProgress.lblRowNumCrnt.Caption = k
  DoEvents

现在用户会看到类似的内容:

Worksheet    2  of     3
      Row  1456 or  2450

上述技术很简单,不涉及对Jon49代码的任何更改。以下技术借鉴了Wrox优秀的 Excel VBA程序员参考,稍微复杂一些,但为您的宏提供了更专业的外观。

创建一个贯穿整个表单的标签。将其命名为“lblToDo”并将其着色为白色。在顶部创建相同大小的另一个标签。将其命名为“lblDone”并将其涂成黑色。

创建代码副本以计算顶部每个工作表中的行数,这样您就可以在执行任何其他操作之前计算总行数“TotalRowsTotal”。

创建一个新变量“TotalRowsCrnt”,将其初始化为零,并为每个工作表中的每一行添加一个变量。

在内部循环中,添加:

frmProgress.lblToDo.Width =  _
        frmProgress.lblDone.Width * TotalRowsCrnt / TotalRowsTotal   

对于我工作的所有组织仍在使用的Excel 2003,这会给出一个进度条,其中黑色Done标签稳定地覆盖白色ToDo标签。更高版本的Excel可能会提供进度条控件作为标准。

我希望这能让您了解如何让您的宏对您的用户更具吸引力。