尽管使用VBA代码可以调出许多Excel内置的对话框,但这些对话框却未必能满足我们的全部需求。
很多时候,我们都希望能自己设计一个交互界面,定义其中的控件及控件的功能,这就需要用到VBA中的另一类常用对象,UserForm对象。
一个用户窗体,就是一个UserForm对象,也就是大家所说的窗体对象,简称窗体。
当在工程中添加一个窗体后,就可以在窗体上自由地添加ActiveX控件,只要通过编写VBA代码为这些控件指定功能,就能利用这些控件与Excel互动;
用户窗体:VBE(开发工具→VB→插入→用户窗体;)
工具箱:视图→工具箱;
listView列表视图:视图→工具箱→工具→附加控件→Microsoft listview control 6.0;
窗体控件是你按alt+f11进入vba编译环境,添加的窗体上,用控件工具箱做出来的,驱动需要vba代码控制,而工作表控件是在工作表上用视图-控件工具箱作出来的,虽然也是代码驱动,但是代码不在vba后台,需要在设计模式察看代码才可以。
图形控件可以设置一些个性化的图标作为按钮,用右键点画出来的图形,选择指定宏,就可以获得几乎和后台窗体以及工作表控件一样的效果,不同的是,绘图作出来的按钮,对代码的调用是一种链接关系.会随文件路径改变而受影响。
表单控件和ActiveX控件虽然都可以在工作表中使用,但它们之间区别很大;表单控件用法单一,只能在工作表中通过设置控件的格式或指定宏来使用,而ActiveX控件拥有很多属性和事件,不但可以在工作表中使用,还可以在用户窗体中使用。如果只是以编辑数据为目的,使用表单控件也许就可以了,但是如果在编辑数据的同时还要进行其他操作,使用ActiveX控件会灵活很多。
事实上,为自己的程序设计操作界面,多数时候我们都是在使用ActiveX控件。
对话框是我们和程序“沟通”,用来传递信息的工具。
但我们并不需要亲自去设计程序所需的每一个对话框,因为VBA已经提供了多种现成的对话框给我们使用。
注意InputBox函数和Application.InputBox方法的区别,后者要复杂得多;
'打开用户窗体:
'打开用户窗体:
Private Sub Workbook_Open()
frmFind.Show
End Sub
With Me.CombFindRange
.AddItem "所有工作簿"
.AddItem "当前工作簿"
.AddItem "当前工作表"
.ListIndex = 2
End With
Me.txtInput.Value = "15"
With Me.CombLookIn
.AddItem "公式"
.AddItem "值"
.AddItem "批注"
.ListIndex = 0
End With
With Me.ListView1
.ColumnHeaders.Add Text:="工作簿", Width:=60
.ColumnHeaders.Add Text:="工作表", Width:=60
.ColumnHeaders.Add Text:="地址", Width:=60
.ColumnHeaders.Add Text:="内容", Width:=130
.ColumnHeaders.Add Text:="公式", Width:=60
End With
End Sub
Private Sub cmdFind_Click()
If Len(txtInput.Text) = 0 Then Exit Sub
Dim objBook As Workbook
Dim objSheet As Worksheet
Dim strToFind As String
Dim lngLookAt As Long
Dim lngLookIn As Long
Dim blnMatchCase As Boolean
Dim blnMatchByte As Boolean
Dim lngListCount As Long
lngLookAt = IIf(chkMatch, xlWhole, xlPart)
lngLookIn = VBA.Choose(CombLookIn.ListIndex + 1, xlFormulas, xlValues, xlComments)
blnMatchCase = chkMatchCase
blnMatchByte = chkMatchByte
strToFind = txtInput.Value
ListView1.ListItems.Clear
On Error GoTo ErrHandle
Select Case CombFindRange.ListIndex
Case Is = 2
Set objSheet = ActiveSheet
Call FindInSheet(objSheet, strToFind, lngLookIn, lngLookAt, blnMatchCase, blnMatchByte)
Case Is = 1
Set objBook = ActiveWorkbook
For Each objSheet In objBook.Worksheets
Call FindInSheet(objSheet, strToFind, lngLookIn, lngLookAt, blnMatchCase, blnMatchByte)
Next
Case Is = 0
For Each objBook In Application.Workbooks
If Not objBook.IsAddin Then
For Each objSheet In objBook.Worksheets
Call FindInSheet(objSheet, strToFind, lngLookIn, lngLookAt, blnMatchCase, blnMatchByte)
Next
End If
Next
End Select
txtInput.SetFocus
lngListCount = ListView1.ListItems.Count
lblTip.Caption = "在" & Me.CombFindRange.Value & "中共找到" & lngListCount & "个匹配单元格"
Set objSheet = Nothing
Set objBook = Nothing
Exit Sub
ErrHandle:
MsgBox Err.Description, vbExcelamation, Me.Caption
'GoTo destroyObj
End Sub
Private Sub FindInSheet(ByVal Sht As Worksheet, _
ByVal FindString As String, _
ByVal LookIn As Long, _
ByVal LookAt As Long, _
ByVal MatchCase As Boolean, _
ByVal MatchByte As Boolean)
Dim c As Range
Dim firstAddress As String
Dim itmX As ListItem
With Sht.UsedRange
Set c = .Find(What:=FindString, LookIn:=LookIn, LookAt:=LookAt, MatchCase:=MatchCase, MatchByte:=MatchByte)
If Not c Is Nothing Then
firstAddress = c.Address
Do
Set itmX = ListView1.ListItems.Add()
itmX.Text = Sht.Parent.Name
itmX.SubItems(1) = Sht.Name
itmX.SubItems(2) = c.Address
itmX.SubItems(3) = Trim(c.Value)
If c.HasFormula Then itmX.SubItems(4) = c.Formula
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End With
Set c = Nothing
Set itmX = Nothing
End Sub
Private Sub ListView1_ItemClick(ByVal Item As MSComctlLib.ListItem)
On Error GoTo ErrHandle
Application.Goto Workbooks(Item.Text).Worksheets(Item.SubItems(1)).Range(Item.SubItems(2))
Exit Sub
ErrHandle:
MsgBox "不能定位到指定的单元格", vbExclamation, Me.Caption
End Sub