刚刚看了一个vb.net 实现动态菜单的例子。觉得很有意思。例子中用的主要技术有:
菜单树 的 操作
treeview的操作
利用堆栈实现菜单树与treeview树成员的对应
利用委托实现对象与事件的关联
因为我是初学者,所以有些词汇用得可能不恰当,另外有些理解也可能有偏差。
这个例子实现了,用户可以在当前菜单的任意一个节点上添加一个子菜单,并为添加的子菜单添加事件。
例子介绍如下:
首先创建一个 vb.net winform application
在form中添加一个菜单,取名为:MainItem,随便添加几个菜单项几项。
添加一个textbox控件, 取名为:txtNewText
添加一个listbox控件, 取名为:lstHandlers
添加一个TreeView控件,取名为:tvMenu
具体代码如下(其中有大部分代码为自动生成):
Public
Class Form1
Class Form1
Inherits System.Windows.Forms.Form
Windows 窗体设计器生成的代码#Region " Windows 窗体设计器生成的代码 "
Public Sub New()Sub New()
MyBase.New()
'该调用是 Windows 窗体设计器所必需的。
InitializeComponent()
'在 InitializeComponent() 调用之后添加任何初始化
End Sub
'窗体重写处置以清理组件列表。
Protected Overloads Overrides Sub Dispose()Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Windows 窗体设计器所必需的
Private components As System.ComponentModel.IContainer
'注意:以下过程是 Windows 窗体设计器所必需的
'可以使用 Windows 窗体设计器修改此过程。
'不要使用代码编辑器修改它。
Friend WithEvents MainMenu As System.Windows.Forms.MainMenu
Friend WithEvents MenuItem1 As System.Windows.Forms.MenuItem
Friend WithEvents MenuItem2 As System.Windows.Forms.MenuItem
Friend WithEvents MenuItem3 As System.Windows.Forms.MenuItem
Friend WithEvents lstHandlers As System.Windows.Forms.ListBox
Friend WithEvents Label3 As System.Windows.Forms.Label
Friend WithEvents tvMenu As System.Windows.Forms.TreeView
Friend WithEvents Label2 As System.Windows.Forms.Label
Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents txtNewText As System.Windows.Forms.TextBox
Friend WithEvents btnAddItem As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.MainMenu = New System.Windows.Forms.MainMenu(Me.components)
Me.MenuItem1 = New System.Windows.Forms.MenuItem
Me.MenuItem2 = New System.Windows.Forms.MenuItem
Me.MenuItem3 = New System.Windows.Forms.MenuItem
Me.lstHandlers = New System.Windows.Forms.ListBox
Me.Label3 = New System.Windows.Forms.Label
Me.tvMenu = New System.Windows.Forms.TreeView
Me.Label2 = New System.Windows.Forms.Label
Me.Label1 = New System.Windows.Forms.Label
Me.txtNewText = New System.Windows.Forms.TextBox
Me.btnAddItem = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'MainMenu
'
Me.MainMenu.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.MenuItem1, Me.MenuItem2, Me.MenuItem3})
'
'MenuItem1
'
Me.MenuItem1.Index = 0
Me.MenuItem1.Text = "菜单1"
'
'MenuItem2
'
Me.MenuItem2.Index = 1
Me.MenuItem2.Text = "菜单2"
'
'MenuItem3
'
Me.MenuItem3.Index = 2
Me.MenuItem3.Text = "菜单3"
'
'lstHandlers
'
Me.lstHandlers.ItemHeight = 12
Me.lstHandlers.Location = New System.Drawing.Point(88, 64)
Me.lstHandlers.Name = "lstHandlers"
Me.lstHandlers.Size = New System.Drawing.Size(136, 112)
Me.lstHandlers.TabIndex = 13
'
'Label3
'
Me.Label3.Location = New System.Drawing.Point(56, 64)
Me.Label3.Name = "Label3"
Me.Label3.Size = New System.Drawing.Size(32, 16)
Me.Label3.TabIndex = 12
Me.Label3.Text = "事件"
'
'tvMenu
'
Me.tvMenu.Location = New System.Drawing.Point(280, 24)
Me.tvMenu.Name = "tvMenu"
Me.tvMenu.Size = New System.Drawing.Size(152, 152)
Me.tvMenu.TabIndex = 11
'
'Label2
'
Me.Label2.Location = New System.Drawing.Point(232, 32)
Me.Label2.Name = "Label2"
Me.Label2.Size = New System.Drawing.Size(48, 16)
Me.Label2.TabIndex = 10
Me.Label2.Text = "添加到"
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(8, 32)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(80, 16)
Me.Label1.TabIndex = 9
Me.Label1.Text = "新菜单项文字"
'
'txtNewText
'
Me.txtNewText.Location = New System.Drawing.Point(88, 24)
Me.txtNewText.Name = "txtNewText"
Me.txtNewText.Size = New System.Drawing.Size(136, 21)
Me.txtNewText.TabIndex = 8
'
'btnAddItem
'
Me.btnAddItem.Location = New System.Drawing.Point(168, 192)
Me.btnAddItem.Name = "btnAddItem"
Me.btnAddItem.Size = New System.Drawing.Size(80, 24)
Me.btnAddItem.TabIndex = 7
Me.btnAddItem.Text = "添加菜单项"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)
Me.ClientSize = New System.Drawing.Size(448, 225)
Me.Controls.Add(Me.lstHandlers)
Me.Controls.Add(Me.Label3)
Me.Controls.Add(Me.tvMenu)
Me.Controls.Add(Me.Label2)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.txtNewText)
Me.Controls.Add(Me.btnAddItem)
Me.Menu = Me.MainMenu
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
#End Region
Private eHandlers(3) As EventHandler '定义事件方法集合
Private Sub ShowHelloWorld()Sub ShowHelloWorld(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Hello World!")
End Sub
Private Sub ShowMenuItemText()Sub ShowMenuItemText(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim mItem As MenuItem
mItem = CType(sender, MenuItem)
MessageBox.Show(mItem.Text)
End Sub
Private Sub ShowMenuItemIndex()Sub ShowMenuItemIndex(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim mItem As MenuItem
mItem = CType(sender, MenuItem)
MessageBox.Show(mItem.Index)
End Sub
Private Sub ShowCurDateTime()Sub ShowCurDateTime(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim strDate As String = DateTime.Now.ToString()
MessageBox.Show(strDate)
End Sub
Private Sub MenuItemToNode()Sub MenuItemToNode(ByVal menuItems As Menu.MenuItemCollection, ByVal targetNodes As TreeNodeCollection)
'TreeNodeCollection 代表一个树结点集合,每一个节点下的儿子节点的集合
'MenuItemCollection 代表一个菜单项的集合,也是菜单树中某一菜单下的一级子菜单的菜单项的集合
Dim subItem As MenuItem
For Each subItem In menuItems
Dim subNode As New TreeNode(subItem.Text)
If subItem.MenuItems.Count > 0 Then
MenuItemToNode(subItem.MenuItems, subNode.Nodes) '递归处理
End If
targetNodes.Add(subNode)
Next
End Sub
Private Function FindMenuItem()Function FindMenuItem(ByVal selectedNode As TreeNode) As MenuItem
Dim indexStack As New Collections.Stack() '定一个堆栈对象
'将树结点从当前节点一直到根的一条路径压入堆栈
Do Until selectedNode Is Nothing
indexStack.Push(selectedNode.Index)
selectedNode = selectedNode.Parent
Loop
'再利用菜单与treeview树一一对应的特点.根据节点的index,找到对应的菜单项.然后沿着路径找到当前的菜单项
Dim menuItem As MenuItem = MainMenu.MenuItems(indexStack.Pop())
Do Until indexStack.Count = 0
menuItem = menuItem.MenuItems(indexStack.Pop())
Loop
'返回当前菜单项
Return menuItem
End Function
Private Sub btnAddItem_Click()Sub btnAddItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddItem.Click
If txtNewText.Text = "" Then Exit Sub
If tvMenu.SelectedNode Is Nothing Then Exit Sub
Dim correspondingMenuItem As MenuItem
Dim newMenuItem As MenuItem
correspondingMenuItem = FindMenuItem(tvMenu.SelectedNode) '将节点转成菜单项
newMenuItem = New MenuItem(txtNewText.Text) '生成新加的菜单项
If lstHandlers.SelectedIndex >= 0 Then
AddHandler newMenuItem.Click, eHandlers(lstHandlers.SelectedIndex) '建立事件的委托
End If
correspondingMenuItem.MenuItems.Add(newMenuItem) '将新菜单加到菜单树中
tvMenu.Nodes.Clear() '清空treeview树
MenuItemToNode(MainMenu.MenuItems, tvMenu.Nodes) '将最新的菜单呈现成树
tvMenu.ExpandAll() '展开树
End Sub
Private Sub Form1_Load()Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MenuItemToNode(MainMenu.MenuItems, tvMenu.Nodes) '将菜单树呈现到treeview中
tvMenu.ExpandAll() '展开他
'将三个事件方法放入集合
eHandlers(0) = AddressOf ShowHelloWorld
eHandlers(1) = AddressOf ShowMenuItemText
eHandlers(2) = AddressOf ShowMenuItemIndex
eHandlers(3) = AddressOf ShowCurDateTime
'将事件方法名字写入列表
Dim i As Integer
For i = 0 To eHandlers.Length - 1
lstHandlers.Items.Add(eHandlers(i).Method.Name)
Next
End Sub
End Class
运行的界面如下: