Excel编程周末速成班第21课:一个用户窗体示例
excelperfect
引言:这是在知识星球App的完美Excel社群中发表的Excel VBA编程系列文章中的一篇,使用一个示例来讲解用户窗体的基础应用。
主要内容:
规划示例工程
创建工作簿
设计窗体
编写代码
验证数据
测试工程
规划工程
一个Excel程序示例,你可能想在现实世界中使用用户窗体来帮助用户输入数据。当然,用户总是可以直接将数据输入到工作表中,那么为什么要为此目的创建程序和用户窗体呢?有以下几个原因:
用户疲劳。长时间盯着工作表行和列的网格可能会导致疲劳并增加出错的机会,设计良好的用户窗体使查看更容易。
更高的准确性。你可以编写代码以确保将每一项数据放置在工作表中的合适的位置,手动输入更容易出错。
数据验证。用户窗体中的代码可以验证输入的数据并执行检查,例如,验证邮政编码是否包含且仅包含五位数字(对于较新的代码,则为九位数字加破折号)。与在后面进行处理相比,在输入之前捕获错误数据要容易得多。
这里是该工程的方案。工作簿用于维护一组人的姓名和地址数据,该工作簿名为Addresses.xlsm,数据所在的工作表也称为Addresses,该工作表包含各种数据项的列标题,如图21-1所示。为了简单起见,我们假设所有地址都在美国。
图21-1:Addresses工作表模板
程序运行时,它将执行以下任务:
1.使Addresses工作表处于活动状态。
2.找到数据的第一个空白行。该工作簿可能包含现有数据,也可能是空白的,如图21-1所示。
3.显示一个用户窗体,使用户可以输入一个人的数据。
4.继续显示用户窗体,直到输入了所有数据。
5.保存工作簿,然后关闭程序。
这个用户窗体本身具有以下功能:
提供用于输入名字(FirstName)、姓氏(LastName)、地址(Address)、城市(City)和五位数邮政编码(ZIP)的文本框控件。
提供一个用于选择state的列表框控件。
显示一个“下一步”命令按钮,该按钮将当前数据保存在工作表中,并再次显示该窗体以输入更多数据。
显示“完成”命令按钮,该按钮保存当前数据,保存工作簿并关闭窗体。
显示一个“取消”命令按钮,该命令按钮放弃当前数据并关闭窗体。
验证没有字段留为空白。
验证邮政编码条目是有效的邮政编码。
步骤1:创建工作簿
要完成的第一个任务是创建Addresses工作簿。按照下面的步骤:
1.启动Excel以打开一个新的空白工作簿。
2.双击工作表上的名称选项卡,然后输入新名称,将Sheet1重命名为Addresses。
3.输入数据列标题,如图21-1所示。你可以根据需要设置它们的格式,但是要确保它们位于单元格A2至单元格F2。
4.将工作簿另存为Address.xlsm。
至此,工作簿模板已完成,你可以继续设计用户窗体。
步骤2:设计窗体
要创建新的空白用户窗体并设置其属性,执行以下操作:
1.按Alt+F11打开VBA编辑器。
2.在工程窗口中,单击标记为VBAProject(Addresses)的条目。
3.选择插入➪用户窗体将一个新的用户窗体添加到工程中。
4.使用属性窗口将窗体的Name属性更改为frmAddresses,并将其Caption属性更改为“地址输入”。
下一步将添加用于数据输入的文本框控件,用于state的复合框控件,用于操作的命令按钮控件,以及用于标识每个文本框和列表框的标签控件。
1.将文本框控件添加到窗体,然后将其Name属性更改为txtFirstName。
2.在该文本框旁边添加一个标签控件,并将其Caption属性更改为“名字:”。
3.再添加四个文本框控件,将Name属性分别更改为txtLastName、txtAddress、txtCity和txtZip。
4.在每个新的文本框控件旁边放置一个标签控件,然后将Caption属性分别设置为“姓氏:”、“地址:”、“城市:”和“邮政编码:”。
5.将复合框控件添加到窗体,并将其Name属性更改为cmbStates,将其Style属性更改为fmStyleDropDownList。
6.在该复合框控件的旁边放置一个标签控件,将其Caption属性设置为“州:”。
7.添加一个命令按钮控件,将其Name属性更改为cmdDone,并将其Caption属性更改为“完成”。
8.添加另一个命令按钮控件,将其Name属性更改为cmdNext,将其Caption属性更改为“下一步”,并将其Default属性更改为True。
9.添加第三个命令按钮控件,将其Name属性更改为cmdCancel,将其Caption属性更改为“取消”,并将其Cancel属性更改为True。
现在,所有必需的控件都在窗体上。使用窗体设计器的格式化命令和工具来根据需要排列和调整控件的大小。完成的设计应该类似于图21-2。
图21-2:放置所有控件之后的窗体
这是检查窗体上控件的选项顺序的好时机。所需的顺序是将六个数据输入控件按正确的顺序放在选项顺序的顶部,然后是三个命令按钮控件。
步骤3:编写初始化代码
此窗体的初始化代码只需要做一件事:为复合框控件加载所有州的缩写。为了简洁起见,本示例中的代码仅将某些州加载到控件中;当然,真正的应用程序需要在复合框中包含所有州。
要添加代码:
1.单击工程窗口中的“查看代码”按钮以打开用户窗体的代码编辑窗口。
2.从窗口左上方的列表中,选择UserForm。
3.从窗口右上方的列表中,选择Initialize。
4.在该事件过程中输入清单21-1中的代码。
清单21-1:用户窗体初始化代码将州名缩写装载到复合框
Private Sub UserForm_Initialize()
'将州名装载到复合框
cmbStates.AddItem 'AL'
cmbStates.AddItem 'AR'
cmbStates.AddItem 'CA'
cmbStates.AddItem 'CO'
cmbStates.AddItem 'FL'
cmbStates.AddItem 'LA'
cmbStates.AddItem'MD'
cmbStates.AddItem 'NC'
cmbStates.AddItem 'NY'
cmbStates.AddItem 'WV'
End Sub
步骤4:限制邮政编码输入数字
示例要求将邮政编码字段中的数据输入限制为数字,这可以认为是数据验证的一种形式。与其在输入后检查数据(下一节中将对某些字段进行的操作),不如直接阻止输入不正确的数据有时更为有效。
在键盘输入到达控件之前对其进行检查的方法是使用KeyDown事件。如你在第20课中所学习的,此事件接收一个参数,该参数标识所按下的键。如果该键可以接受,则将其传递;否则取消。
在VBA联机帮助中的KeyCode值列表中,你可以看到键0到9的代码值为48到57。因此,如果KeyDown事件过程接收到48至57范围内的KeyCode参数,则输入的是一个数字并可以传递该数字。任何其他值都会被取消。
技巧:你可以通过设置其MaxLength属性将txtZip文本框中的数据限制为5个字符,尽管在此项目中未执行此操作。
要将代码添加到窗体,打开窗体的代码编辑窗口,然后为txtZip控件添加KeyDown事件过程,将清单21-2中的代码添加到该过程中。注意使用Beep语句,如果按下了不正确的键,它将导致系统发出声音。
清单21-2:文本框的KeyDown事件过程仅传递数字
Private Sub txtZip_KeyDown(ByVal KeyCode AsMSForms.ReturnInteger, ByVal Shift As Integer)
'仅传递数字
If KeyCode < 48 Or KeyCode > 57 Then
KeyCode = 0
Beep
End If
End Sub
注意:如清单21-2所示,文本框仅接受在键盘顶部输入的数字,而不接受使用数字键盘输入的数字。修改代码使之也可以接受数字键盘输入是一个很好的编程练习。
步骤5:编写数据验证代码
当用户单击“下一步”或“完成”按钮时,验证代码将检查数据。需要检查的具体项目为:
名字、姓氏、地址和城市字段不能为空。
选择州。
邮政编码字段包含五个字符。因为此字段的输入已限制为数字,所以这是所有需要的验证。
如果验证成功,则将数据输入工作表中,并清除窗体且再次显示该窗体以供其他输入。或者,如果选择了“完成”按钮,则关闭窗体。你可以看到,当用户单击“下一步”或“完成”按钮时,将执行验证。因此,不应将验证代码放在按钮的Click事件过程中,而应放在它自己的过程中。然后可以从“完成”和“下一步”按钮的Click事件过程中调用此过程。
按照以下步骤创建验证过程:
1.显示用户窗体的代码编辑窗口。
2.选择插入➪过程,打开“添加过程”对话框。
3.输入ValidateData作为过程名称;在类型下选择“函数”。
4.单击确定。
注意:验证代码放置在函数中(而不是子过程),因此它可以将值返回给调用程序:如果验证成功,则返回True;如果失败,则返回False。
验证过程的代码如清单21-3所示。注意,除了函数中的代码外,返回说明符AsBoolean已添加到函数的第一行。你应该将此清单中的代码添加到你的程序中。
清单21-3:数据验证函数
Public Function ValidateData() As Boolean
'如果用户窗体中的数据完整,则返回True,否则返回False。
'显示消息来指明问题。
If txtFirstName.Value = '' Then
MsgBox '你必须输入名字.'
ValidateData = False
ExitFunction
End If
If txtLastName.Value = '' Then
MsgBox '你必须输入姓氏.'
ValidateData = False
ExitFunction
End If
If txtAddress.Value= '' Then
MsgBox '你必须输入地址.'
ValidateData = False
ExitFunction
End If
If txtCity.Value = '' Then
MsgBox '你必须输入城市.'
ValidateData = False
ExitFunction
End If
If cmbStates.Value = '' Then
MsgBox '你必须选择州.'
ValidateData = False
ExitFunction
End If
If txtZip.TextLength <> 5 Then
MsgBox '你必须输入5位数的邮政编码.'
ValidateData = False
ExitFunction
End If
ValidateData = True
End Function
步骤6:完成该工程
为了完成此工程,仅需要三个命令按钮控件的Click事件过程。重申一下,这是命令按钮应该执行的操作:
“下一步”按钮验证数据。如果验证成功,则将数据输入工作表中,并清除该窗体以输入下一个地址。如果验证失败,则窗体将保留其数据,以便用户可以根据需要进行更正。
“完成”按钮执行与“下一步”按钮相同的任务,但有一个例外:如果验证成功,则在工作表中输入数据后,关闭窗体。
“取消”按钮将放弃当前在窗体中输入的所有数据,然后关闭该窗体。
你可能已经注意到“完成”和“下一步”按钮共享一个任务,该任务正在工作表中输入经过验证的数据。每当需要在不止一种情况下执行任务时,程序员都会将此视为将所需代码放入一个过程中的机会。如果你创建了将数据从窗体传输到工作表的过程,则“完成”和“下一步”按钮的Click事件过程都可以调用此过程。
同时,该窗体需要代码以清除其控件中的所有数据。当然,在单击“下一步”按钮时,这是必需的,在单击“取消”或“完成”按钮时,这也是必需的。即使使用Hide方法隐藏了该窗体,它在下次显示时仍将所有数据保留在其控件中。因此,需要清除控件。将每个控件的Value属性设置为空白字符串很简单。这段代码被放在名为ClearForm的过程中,如清单21-4所示。下面将此过程添加到窗体中。
清单21-4:ClearForm过程会清除窗体控件中的所有数据
Public Sub ClearForm()
'清除窗体中的所有数据
txtFirstName.Value = ''
txtLastName.Value = ''
txtAddress.Value = ''
txtCity.Value = ''
txtZip.Value= ''
cmbStates.Value = ''
End Sub
在工作表中输入数据要求程序找到第一个空数据行。你知道第一列标题位于单元格A2中。这意味着第一行空白开始于单元格A3或它下面的任何单元格中。有几种方法可以识别第一个空行。这里使用其中的一种,如下:
1.从单元格A2开始作为参考点。
2.使用CurrentRegion属性获取包含标题行和所有现有数据的区域。
3.使用Offset方法以原始区域中的行数获得区域偏移。此新区域比原始区域低一行,并且在第一个空行中包含六个单元格。
4.使用Cells属性访问此区域内的单个单元格以插入数据。
清单21-5显示了EnterDataInWorksheet过程的代码,使用你已经学习的技术将此过程添加到用户窗体中。
清单21-5:EnterDataInWorksheet过程
Public Sub EnterDataInWorksheet()
'从用户窗体中复制数据到工作表中的下一个空行
Dim r AsRange, r1 As Range
Set r =Worksheets('Addresses').Range('A2').CurrentRegion
Set r1 =r.Offset(r.Rows.Count, 0)
r1.Cells(1).Value = txtFirstName.Value
r1.Cells(2).Value = txtLastName.Value
r1.Cells(3).Value = txtAddress.Value
r1.Cells(4).Value = txtCity.Value
r1.Cells(5).Value= cmbStates.Value
r1.Cells(6).Value = txtZip.Value
End Sub
现在已经编写了数据输入的过程,该工程只需要Click事件过程即可完成三个命令按钮控件。清单21-6中显示了代码。注意,这三个事件过程中的每一个都调用了先前创建的ClearForm过程。在用户窗体中输入这里的代码,即可开始试运行该工程。
清单21-6:命令按钮控件的Click事件过程
Private Sub cmdCancel_Click()
ClearForm
Me.Hide
End Sub
Private Sub cmdDone_Click()
If ValidateData = True Then
EnterDataInWorksheet
ClearForm
Me.Hide
End If
End Sub
Private Sub cmdNext_Click()
If ValidateData = True Then
EnterDataInWorksheet
ClearForm
End If
End Sub
步骤7:测试该工程
你可以通过在VBA编辑器中打开用户窗体时按F5来测试工程,还可以编写一个使用Show方法显示窗体的宏。图21-3显示了正在运行的程序。试用后,你会发现,与直接在工作簿中输入数据相比,此程序和用户窗体使数据输入变得更容易。
图21-3:运行程序输入地址
要点回顾
本课程引导你完成创建使用用户窗体进行数据输入的真实程序的完整过程。
在开始编程之前计划项目总是一个好主意。
数据验证是任何数据输入程序的重要组成部分。
可以在输入数据之后或输入数据时执行数据验证。
当你的代码将在程序的多个位置中使用时,将其放在单独的过程中。
自我测评
1.请说明使用用户窗体进行数据输入的两个好处。
2.命名窗体初始化代码可能执行的一项任务。
3.在哪个事件下放置限制输入到文本框控件中的某些字符的代码?
VBA学习信息
本文为知识星球:完美Excel社群正在陆续推出的《Excel编程周末速成班》系列中的一篇,到2020年12月27日,此系列已更新至第21课。下面是第1课至第21课的目录:
第1课:MicrosoftExcel编程——为什么及怎么做
第2课:VBA代码编辑器
第3课:Excel对象模型
第4课:VBA语法和数据
第5课:运算符
第6课:控制结构
第7课:过程和模块
第8课:处理日期和时间
第9课:处理文本
第10课:使用Ranges和Selections
第11课:处理列(Columns),行(Rows)和单元格(Cells)
第12课:使用自定义公式编程
第13课:使用Excel内置函数编程
第14课:格式化工作表
第15课:查找和替换操作
第16课:图表编程简介
第17课:高级的图表编程技术
第18课:使用用户窗体创建自定义对话框
第19课:用户窗体控件
第20课:用户窗体编程高级技术