VBA学习笔记62: 窗体与控件综合实例
学习资源:《Excel VBA从入门到进阶》第62集 by兰色幻想
窗体的内容已经学习完了,这节试着用前几节窗体的内容来把入库单弄成窗体吧。
一、列举想实现的功能:
- 出库日期选择——添加日期控件:DTPicker
- 出库单号码——点击微调项可以递增或递减文本框的号码,和当号码不输入时,不能离开该文本框。
- 在商品代码里按回车或点击右侧的按钮可以打开价格表窗口。
- 价格表需要在窗体加载时即完成treeview控件中的单价信息导入,同时也要完成listview控件的标题行生成。
- 用鼠标单击或者按回车键后,可以把商品名称、型号以及单价输入到相应的文本框里,然后关闭该窗口回到输入主界面,并且焦点转向销售数量后面文本框里。
- 当输入数量时,自动计算销售金额。输入完成按回车,可以自动把本条信息导入到下面的listview中,并且焦点转到商品代码框中。
- 双击listview可以清空所有记录;右键单击可以提示是否删除选中的记录,如果选是则删除选中的记录。
- 点击输入,可以把listview中的数据添加到出库表中。出库单号码自动+1,焦点转到商品代码框中。
二、代码详解:
- 出库日期选择——添加日期控件:DTPicker
不多说,回顾点击以下链接,直接添加日期控件:DTPicker即可。
2. 出库单号码——点击微调项可以递增或递减文本框的号码,和当号码为输入时不能离开该文本框。
微调按钮的上下幅度通过Smallchange属性设置,然后数值显示用的是SpinDown事件和SpinUp事件。(复习链接↓)
夏西蓝:VBA学习笔记58:选项按钮、复选框、框架、滚动条、微调、图像与多页
不允许离开,则是Exit事件,判断语句,如果号码的文本框值为空,就禁止离开。
① SpinDown事件:点击向下的按钮出库单号码在原来的基础上+1。
Private Sub SpinButton1_SpinDown()
TextBox2.Text = Format(Val(TextBox2) + 1, "000") '点击向下的按钮出库单号码在原来的基础上加1
End Sub
② SpinUp事件:点击向上的按钮出库单号码在原来的基础上-1。
Private Sub SpinButton1_SpinUp()
TextBox2.Text = Format(Val(TextBox2) - 1, "000") '点击向上的按钮出库单号码在原来的基础上减1
End Sub
③ Exit事件:出库单号码强制输入,否则不允许离开。
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean) '出库单号码强制输入,否则不允许离开
If TextBox2.Text = "" Then
Cancel = True '取消离开操作
End If
End Sub
3. 回车或点击按钮打开价格表窗口
价格表窗口用多页控件设置,因为多页控件的值从0开始,所以出库单页面是0,而价格单的页面就是1。
回车按钮的值是13,用keydown事件判断按钮的值,确认keycode为13后,跳转到价格单页面(1)。
Private Sub TextBox3_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then
Me.MultiPage1.Value = 1
End If
End Sub
单击打开价格单的话,就是单击事件了。
Private Sub CommandButton3_Click() '点击按钮打开单价窗口
Me.MultiPage1.Value = 1
End Sub
4. 价格表需要在窗体加载时即完成treeview控件中的单价信息导入,同时也要完成listview控件的标题行生成。
窗体加载时,listview都已生成,用UserForm_Initialize事件,这里设置listview的标题行、格式、多页控件的显示等。
Private Sub UserForm_Initialize()
'Dim ITM As ListItem
ListView1.ColumnHeaders.Add 1, , "销售日期", ListView1.Width / 8 '设置第1列
ListView1.ColumnHeaders.Add 2, , "出库单号", ListView1.Width / 8, lvwColumnCenter '设置第2列
ListView1.ColumnHeaders.Add 3, , "商品代码", ListView1.Width / 8, lvwColumnCenter '设置第3列
ListView1.ColumnHeaders.Add 4, , "商品名称", ListView1.Width / 8, lvwColumnCenter '设置第4列
ListView1.ColumnHeaders.Add 5, , "型号", ListView1.Width / 8, lvwColumnCenter '设置第5列
ListView1.ColumnHeaders.Add 6, , "销售数量", ListView1.Width / 9, lvwColumnCenter '设置第6列
ListView1.ColumnHeaders.Add 7, , "销售单价", ListView1.Width / 8, lvwColumnCenter '设置第7列
ListView1.ColumnHeaders.Add 8, , "销售金额", ListView1.Width / 8, lvwColumnCenter '设置第8列
ListView1.View = lvwReport '设置为报告格式
ListView1.Gridlines = True '显示表格线
ListView1.FullRowSelect = True '可以选取整行
ListView1.MultiSelect = True
Call 添加Treeview数据
Me.MultiPage1.Value = 0 '显示输入界面
Me.MultiPage1.Style = 2 '隐藏选项卡
End Sub
在上面我们也看到,价格表准备用treeview来展示,所以这里也需加载treeview的内容。为方便查看,上面用call语句来引用Treeview数据。这里用到的知识点是treeview的数据导入。
价格表的数据放在价格表.sheet里面。
Sub 添加Treeview数据()
Dim Nodx As Node
Dim arr, d As New Dictionary
Dim mykey, sr, x
TreeView1.ImageList = ImageList1 '从imagelist控件中提取图片
arr = Sheets("价格表").Range("A2:D" & Sheets("价格表").Range("a65535").End(xlUp).Row)
For x = 1 To UBound(arr)
mykey = arr(x, 1) & "," & arr(x, 2) & "," & arr(x, 3) & "," & arr(x, 4)
'把商品所有信息连接起来,后面放在key里存放,以便随时调用
sr = arr(x, 3) & "(" & arr(x, 1) & ") 价格:" & arr(x, 4)
'设置节点显示的内容
If Not d.Exists(arr(x, 2)) Then '如果该顶级节点不存在
d(arr(x, 2)) = "" '添加到字典里,以便下次判断是否存在
Set Nodx = TreeView1.Nodes.Add(, , arr(x, 2), arr(x, 2), 1, 1) '添加顶级节点
Set Nodx = TreeView1.Nodes.Add(arr(x, 2), tvwChild, mykey, sr, 2, 2) '添加子节点
Nodx.EnsureVisible '打开节点
Set Nodx = TreeView1.Nodes.Add(arr(x, 2), tvwChild, mykey, sr, 2, 2) '添加子节点
End If
Next x
End Sub
5. 用鼠标单击或者按回车键后,可以把商品名称、型号以及单价输入到相应的文本框里,然后关闭该窗口回到输入主界面,并且焦点转向销售数量后面文本框里。
①单击事件
Private Sub TreeView1_Click() '单击事件
Dim MyItem As Node
Set MyItem = TreeView1.SelectedItem 'SelectedItem正在选取的节点
If MyItem.Parent Is Nothing Then '不能选取一级节点
Exit Sub
'从key取出值折分开分别放在四个文本框内
TextBox3.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(0)
TextBox4.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(1)
TextBox8.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(2)
TextBox6.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(3)
Me.MultiPage1.Value = 0 '跳转回入库单界面
TextBox5.SetFocus '光标移动至到销售数量文本框
End If
End Sub
②回车事件
Private Sub TreeView1_KeyDown(KeyCode As Integer, ByVal Shift As Integer) '按钮事件
Dim MyItem As Node
Set MyItem = TreeView1.SelectedItem 'SelectedItem正在选取的节点
If KeyCode = 13 Then '点击回车键
If MyItem.Parent Is Nothing Then '不能选取一级节点
Exit Sub
'从key取出值折分开分别放在四个文本框内
TextBox3.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(0)
TextBox4.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(1)
TextBox8.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(2)
TextBox6.Text = Split(Me.TreeView1.SelectedItem.Key, ",")(3)
Me.MultiPage1.Value = 0 '跳转回入库单界面
TextBox5.SetFocus '光标移动至到销售数量文本框
End If
End If
End Sub
6. 当输入数量时,自动计算销售金额。输入完成按回车,可以自动把本条信息导入到下面的listview中,并且焦点转到商品代码框中。
①首先是change事件,输入数量就自动计算金额。
Private Sub TextBox5_Change()
TextBox7.Value = Val(TextBox5) * Val(TextBox6.Value) '输入数量时自动计算金额
End Sub
②输入完成,按回车,把数据导入listview中
Private Sub TextBox5_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim lv As ListItem
'按回车且文本框数值不为0
If KeyCode = 13 And TextBox5 <> "" Then
'向listview中框添加记录
With ListView1
Set lv = .ListItems.Add
lv.Text = DTPicker1.Value
lv.SubItems(1) = TextBox2.Text
lv.SubItems(2) = TextBox3.Text
lv.SubItems(3) = TextBox4.Text
lv.SubItems(4) = TextBox8.Text
lv.SubItems(5) = TextBox5.Text
lv.SubItems(6) = TextBox6.Text
lv.SubItems(7) = TextBox7.Text
TextBox5 = ""
TextBox3 = ""
TextBox3.SetFocus
End With
End If
End Sub
7. 双击listview可以清空所有记录;右键单击可以提示是否删除选中的记录,如果选是则删除选中的记录。
① 双击事件,双击后进行询问再次确认以免误删。
Private Sub ListView1_DblClick() '为listview控件增加清空所有行的功能
If MsgBox("你要清空所有行吗", vbOKCancel) = vbOK Then
ListView1.ListItems.Clear '用ListItems对象的clear方法可以清空所有行
End If
End Sub
② VBA中没有右键单击事件,但我们可以用点击事件+按钮判断(按右键是2)。同样删除前最后先进行询问,以免误删。
Private Sub ListView1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)
If Button = 2 Then
If MsgBox("你要删除选取的行吗", vbOKCancel) = vbOK Then
ListView1.ListItems.Remove ListView1.SelectedItem.Index '用ListItems对象的clear方法可以清空所有行
End If
End If
End Sub
8. 完成整张出库单的输入,点击“输入”按钮,可以把listview中的数据添加到出库表中。出库单号码自动+1,焦点转到商品代码框中。
Private Sub CommandButton1_Click() '把listview列表中的数据输出到工作表中
Dim arr()
Dim icount As Integer, y As Integer, x
icount = ListView1.ListItems.Count 'ListItems.Count 返回总行数
ReDim arr(1 To icount, 1 To 8)
For x = 1 To icount '把数据导入至数组
arr(x, 1) = ListView1.ListItems(x).Text '把listview第1列(text)放在数组第一列
For y = 1 To 7
arr(x, y + 1) = ListView1.ListItems(x).SubItems(y)
Next y
Next x
Range("a65536").End(xlUp).Offset(1, 0).Resize(icount, 8) = arr