Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 9628|回复: 17

[VBA] 036-创建多级下拉菜单-疑难千寻千解丛书(VBA)

  [复制链接]
发表于 2011-2-21 10:15 | 显示全部楼层 |阅读模式
ET疑难千寻千解丛书之EXCEL2010编程与实践
罗刚君 章兰新 黄朝阳 编著

疑难36
如何引用数据表创建多级下拉菜单
数据有效性可以实现下拉菜单,但只能一级。那么可以实现二级菜单吗?例如利用图所示的数据
产生如图所示的二级菜单,当单击单元格时,产生二级菜单;选择第二级菜单时可以在单元格分别产生部门和姓名,即同时输入一级和二级菜单的字符。

è解决方案
数据有效性功能无法修改,但可以通过自定义二级菜单的方式来处理。ShowPopup方法可以将二级菜单显示在活动单元格处,从而打造出类似于数据有效性下拉列表的二级菜单。最后利用ActionControl属性获取用户所单击的菜单字符,并导入到单元格中。
简单而言,就是利用工作簿事件SheetSelectionChange,在选择指定的单元格时利用CommandBars.Add创建一级和二级菜单,而当用户选择菜单时,将菜单的文字标题导入到单元格中。
í操作方法
步骤1
按【Alt+F11】组合键打开VBE窗口。
步骤2
选择菜单“插入”→“模块”,并输入以下代码:

  1. Sub 选项() '用于指定哪个区域可以产生二级菜单
  2.   Dim i As String, adds As String, sht As Worksheet
  3.   '确认是否存在“数据”工作表
  4.   On Error Resume Next
  5.   Set sht = Sheets("数据")
  6.   If err.Number <> 0 Then MsgBox "请建立一个名为“数据”的工作表,用于存放菜单
  7.   所需要的数据", , "确认数据表": GoTo err
  8.   err.Clear
  9.   On Error GoTo err
  10.   '如果选择的是单元格,那么将选区地址赋予变量adds,否则将“B:B”赋予变量
  11.   If TypeName(Selection) = "Range" Then adds = Selection.Address(0, 0) Else
  12.   adds = "B:B"
  13.   i = Application.InputBox("你想控制哪一个区域" & vbCrLf & "如果想关闭本功能,
  14.   单击取消按钮即可。", "请选择区域", adds, , , , , 8).Address(0, 0)
  15.   SaveSetting "MyApp", "only", "only", i '将用户选择的单元格地址存入注册表
  16.   Exit Sub '退出程序
  17. err:
  18.   SaveSetting "MyApp", "only", "only", "" '在注册表中写入一个空字符
  19. End Sub
  20. 以上过程用于让用户指定在哪个区域产生二级菜单,可以利用【Ctrl】键多选。而用户选择的区域地址将会存储在注册表中。
  21. 步骤3        如果VBE编辑器左边没有对象浏览器,那么选择菜单“视图”→“对象浏览器”调出对象浏览器窗口。然后双击“ThisWorkbook”进入代码窗口,并输入以下工作簿级别事件过程代码:
  22. Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
  23.   If GetSetting("MyApp", "only", "only", "") = "" Then Exit Sub
  24.   '如果注册表中没有值则退出
  25.   If Target.Count > 1 Then Exit Sub '如果选择区域则退出
  26.   On Error Resume Next
  27.   Dim sht As Worksheet
  28.   Set sht = Sheets("数据") '将数据表赋予变量sht
  29.   If err <> 0 Then err.Clear: Exit Sub
  30.    '如果有错误(即没有“数据”工作表)那么退出
  31.   If sht.Range("a1") = "" Then MsgBox "请在数据表中输入数据,必须从A1开始,数
  32.   据区不要留空", vbOKOnly, "提示": Exit Sub
  33.   Dim a As Range
  34.   '判断注册表中记录的单元格与活动单元格是否重叠
  35.   Set a = Intersect(Range(GetSetting("MyApp", "only", "only", "")),
  36.   ActiveCell)
  37.   If a Is Nothing Then Exit Sub '如果不在指定区域则退出
  38.   Dim i, j, addss As String
  39.   With Application.CommandBars.Add("临时菜单", msoBarPopup, , 1)
  40.   '创建一个快捷菜单
  41.     With .Controls.Add(Type:=msoControlButton) '添加一个子菜单
  42.       .Caption = "请选择" '指定显示标题
  43.       .FaceId = 136  '指定图标
  44.     End With
  45.     For i = 1 To sht.Cells(1, Columns.Count).End(xlToLeft).Column
  46.     '创建一级菜单
  47.       If WorksheetFunction.CountA(sht.Rows(2)) = 0 Then
  48.       '如果第二行为空则只创建一级菜单
  49. With .Controls.Add(Type:=msoControlButton) '开始创建一级菜单
  50.           .Caption = sht.Cells(1, i).Text '菜单显示的标题
  51.           .Style = msoButtonIconAndCaption '同时显示文本和图标
  52.           .FaceId = 70 + i   '指定图文件
  53.           .OnAction = "输入" '指定菜单对应的宏名
  54.         End With
  55.       Else  '第二行非空则创建二级菜单
  56.         With .Controls.Add(msoControlPopup, 1, , , 1) '开如创建二级菜单
  57.           .BeginGroup = True '全部产生一条横线分隔开
  58.           .Caption = sht.Cells(1, i).Text '指定二级菜单标题
  59.           For j = 2 To sht.Cells(Rows.Count, i).End(xlUp).Row
  60.             If sht.Cells(j, i) = "" Then GoTo AA '如果为空则不创建子菜单
  61.             Set oCtrl = .Controls.Add(Type:=msoControlButton) '创建子菜单
  62.             With oCtrl '对子菜单指定标题、宏名和图标
  63.               .Caption = sht.Cells(j, i)
  64.               .OnAction = "输入"
  65.               .FaceId = 69 + j
  66.             End With
  67. AA:
  68.           Next
  69.         End With
  70.       End If
  71.      Next
  72.     .ShowPopup '显示工具栏
  73.   End With
  74.   Application.CommandBars("临时菜单").Delete '删除工具栏
  75. End Sub
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
 楼主| 发表于 2011-2-21 10:15 | 显示全部楼层
以上事件为工作簿级别的SelectionChange事件,表示用户选择单元格时执行对应的过程。本过程首先判断当前选区是否与注册表中存储的单元格重叠,如果重叠则创建二级菜单,调用“数据”工作表中指定区域的文本作为菜单的显示标题。
步骤4
返回模块中,继续输入过程“输入”的代码:

  1. Sub 输入() '当单击二级菜单时,将菜单的标题字符写入单元格
  2.   AA = CommandBars.ActionControl.Caption '记录当前菜单的标题
  3.   '在数据表中查找变量aa,并返回找到的目标所在列的第一个单元格(即一级菜单),并写入
  4.   '活动单元格
  5.   ActiveCell = Sheets("数据").Cells.Find(What:=AA, LookAt:=xlWhole). EntireColumn.Cells(1)
  6. '如果“数据”工作表第二行有数据,那么将当前菜单的文字写入右边一个单元格(即二级菜单)
  7.   If WorksheetFunction.CountA(Sheets("数据").Rows(2)) <> 0 Then
  8.     ActiveCell.Offset(0, 1) = AA
  9.   End If
  10. End Sub
复制代码
以上过程是单击菜单时执行的宏过程,用于将一级和二级菜单的显示标题导出到活动单元格及活动单元格右边一个单元格。如果只有一级菜单,则只导入一级菜单的文字。
步骤5
返回工作表界面,在“数据”工作表中按所示方式输入数据。其中第一行用于创建一级菜单,其他数据用于创建二级菜单;在区域中间不能有空白单元格。
步骤6
切换到“职工表”,选择“开发工具”选项卡,单击【宏】按钮,在弹出的对话框中选择过程名“选项”并单击【执行】按钮,程序会弹出对话框等待用户指定需要产生二级菜单的区域,如所示。选择一个或者多个区域,程序会将地址保存在注册表中。
步骤7
单击B2:B10区域中任意单元格,将弹出上所示的二级菜单。如果选择菜单“业务部”→“胡大链”,那么B列和C列同时产生“业务部”和“胡大链”,如所示。

步骤8
切换到“数据”工作表,将第一行以外的数据删除。返回“职工表”,选择B4单元格,此时将弹出一级菜单,如所示。
步骤9
切换到“数据”工作表,恢复删除前的所有数据,并且在E列追加部门“策划部”和姓名“胡军”、“张英姿”。进入“职工表”,选择B2单元格,在弹出的菜单中也自动追加对应的二级菜单,如所示。

=============================
上摘自《EXCEL2010编程与实践》

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2011-2-21 10:36 | 显示全部楼层
最好老师能做个插件或加载的宏,我不知道怎么弄啊
回复

使用道具 举报

发表于 2011-2-23 12:14 | 显示全部楼层
有点复杂
回复

使用道具 举报

发表于 2011-2-23 11:07 | 显示全部楼层
非常复杂。
回复

使用道具 举报

发表于 2011-4-9 20:58 | 显示全部楼层
{:011:}{:011:}{:011:}{:011:}
回复

使用道具 举报

发表于 2011-4-20 15:55 | 显示全部楼层
我就直接没看懂!太复杂了啊!
回复

使用道具 举报

发表于 2011-5-26 12:53 | 显示全部楼层
没看懂但还是顶一下,不知道什么时候才可以学习VBA呢?
回复

使用道具 举报

发表于 2011-5-24 20:46 | 显示全部楼层
好贴~~值得学习和研究!
回复

使用道具 举报

发表于 2012-3-10 20:25 | 显示全部楼层
感谢管理员小妖老师,十分详细,解决了我大问题,还有一点想请教,1、若设定控制区域为B列,所有的工作表B列都会出现二级菜单,若不想这样,有办法解决吗?2、若加入三级菜单该如何写代码,盼指点,谢谢,附件已经上传

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-6-1 19:31 , Processed in 0.262078 second(s), 7 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表