尽管使用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

多工作簿查找

控件始化:

Private Sub UserForm_Initialize()

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