我正在使用包含三个数据工作表的工作簿。每个工作表都有一个合同编号列。必须排除某些合同并在单独的工作表中注明。
我想创建Excel VBA宏:
对于用户输入的'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中不存在合同号,我会收到“对象变量或未设置块”之类的错误。一旦我可以修复此错误,我将需要通过循环为用户输入的每个合同号运行此过程。任何有关调试错误或为此设置循环的帮助将非常感激。
谢谢!
答案 0 :(得分:3)
InputBox
输入合约编号(例如,逗号分隔)。使用Split
函数拆分结果。 wks.visible=xlVeryHidden
,其中wks
是worksheet
个对象)。rFound=saArray
打印2D数组到找到的工作表(其中rFound
是range
对象,saArray
是2D数组。大量使用录制宏来学习语法。
有关检索和打印到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可能会提供进度条控件作为标准。
我希望这能让您了解如何让您的宏对您的用户更具吸引力。