上一篇博客主要介绍的是按钮的拖拽复制功能。这次把其他的功能也整理了一下。
保存布局主要涉及的功能如下按钮的:动态加载RectangleShape控件,拖拽复制,复制出来了的按钮可以在固定的方格内移动,当两个按钮重合的时候实现交换,实现布局的保存。
下面简单说一下这里面设计到的知识:
一、动态加载RectangleShape控件:运用此控件需要添加引用ImportsMicrosoft.VisualBasic.PowerPacks。这里需要注意涉及到一个ShapeContainer类。在设计时想容器控件添加线条或形状控件时,会自动创建一个ShapeContainer对象(不存在)。如果实在在运行时自动加载,就需要New的方法创建一个ShapeContainer对象(代码有体现)。这些线条或形状控件的Parent属性设置为ShapeContainer的属性。ShapeContainer的Parent属性设置为线条或形状所添加到的窗体或容器控件。
二、拖拽复制:此功能的核心就是,从一个到另一位置改变,这里的改变不仅涉及到位置的改变,还涉及到按钮的实例化和复制。主要涉及到三个涉及三个事件上篇博客已涉及,就不在赘述。
三、复制出来了的按钮可以在方格内移动:核心也是位置的改变,这里只是单纯的位置改变。这里设计到三个事件,btn_MouseDown,btn_MouseMove,btn_MouseUp就可以实现位置的改变。这里需要注意的是,由于btn是实例化之后产生的新按钮,要想实现它的事件需要给控件添加事件:如
AddHandler btn.MouseDown, AddressOfbtn_MouseDown。
四、当两个按钮重合的时候实现交换:为了避免同一位置有两个按钮,可以此方法解决。
五、按钮的删除与清空:添加一个,ContexMenuStrip控件,给它赋予事件,然后右键调用此控件的即可,效果图下面将会显示。
六、实现布局的保存:暂无实现,思路:把界面的布局信息写入到XML中,再次重启的时候重新加载。
下面将这块的代码展示给大家,还请指正:
Imports Microsoft.VisualBasic.PowerPacks
Imports System.Windows.Forms
Public Class Form1
Dim Cx As Single
Dim Cy As Single
Dim canvas As ShapeContainer = New ShapeContainer
Dim houseLayout() As RectangleShape = New RectangleShape(24) {}
Dim moves As Boolean = False
Dim pt, ps As Point 'pt临时坐标,ps原坐标
Dim btn As Button
'动态生成矩形框
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim i As Integer
canvas.Parent = Panel1
'动态产生矩形框
canvas.Location = New Point(0, 0)
canvas.Margin = New Padding(0)
canvas.Name = "canvas"
canvas.Size = Panel1.Size
canvas.TabStop = False '失焦
Panel1.Controls.Add(canvas) '把控件加载到Panel1上
For i = 0 To houseLayout.Length - 1
Dim x As Integer = 20
Dim y As Integer = 25
Dim a As Integer = 5 '每行最多放a个,确定a的值即可
Dim quYu As Integer
Dim quInt As Integer
quInt = i \ a '取整,第几列
quYu = i Mod a
x = x + quInt * 69
y = y + quYu * 65
houseLayout(i) = New RectangleShape(canvas)
houseLayout(i).Name = "shape" + i.ToString("00")
'在这里默认的是矩形左上角的起始点
houseLayout(i).Location = New Point(x, y)
houseLayout(i).BackColor = Color.Transparent
houseLayout(i).BorderStyle = Drawing2D.DashStyle.Dash
houseLayout(i).Cursor = Cursors.Default
houseLayout(i).Size = New Size(69, 65)
Next
End Sub
'按下按钮产生的效果
Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
If (e.Button = Windows.Forms.MouseButtons.Left) Then
Button1.DoDragDrop(Button1, DragDropEffects.Copy Or DragDropEffects.Move)
End If
End Sub
'当Button 被拖拽到WindForm 上时候,鼠标效果出现
Private Sub Form1_DragEnter(sender As Object, e As DragEventArgs) Handles MyBase.DragEnter, Panel1.DragEnter, Button1.DragEnter
If (e.Data.GetDataPresent(GetType(Button))) Then
e.Effect = DragDropEffects.Move
End If
End Sub
'拖拽释放后,在矩形框动态生成按钮
Private Sub Panel1_DragDrop(sender As Object, e As DragEventArgs) Handles Panel1.DragDrop
Dim p As Point = New Point(0, 0)
'计算鼠标在panel中的相对位置
p.X = e.X - CType(sender, Panel).Left - 4
p.Y = e.Y - CType(sender, Panel).Top - 15
'根据相对位置,找对应的RectangleShape
Dim rs As RectangleShape = GetRectangleShape(Me.PointToClient(p))
'返回的对象为空
If (IsNothing(rs)) Then
Exit Sub
End If
'拖放完毕之后,自动生成新按钮
Dim btn = New Button
Panel1.Controls.Add(btn)
btn.Tag = rs.Name.Substring(5, 2) '给新控件命名
btn.Text = rs.Name.Substring(5, 2) '可以验证按钮交换
btn.Size = New Size(rs.Size.Width + 1, rs.Size.Height + 1)
btn.Location = rs.Location
btn.BackgroundImage = Button1.BackgroundImage
'把控件放到最顶层
btn.BringToFront()
'右键菜单
btn.ContextMenuStrip = ContextMenuStrip1
'实例化子类的控件会产生的鼠标单击事件()
AddHandler btn.MouseDown, AddressOf btn_MouseDown
AddHandler btn.MouseMove, AddressOf btn_MouseMove
AddHandler btn.MouseUp, AddressOf btn_MouseUp
End Sub
'实例化按钮的按下按钮
Sub btn_MouseDown(sender As Object, e As MouseEventArgs)
If e.Button = MouseButtons.Left Then
ps = sender.Location '原坐标
pt = Cursor.Position '临时坐标
moves = True
ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
moves = False
btn = sender
End If
End Sub
'拖动按钮
Sub btn_MouseMove(sender As Object, e As MouseEventArgs)
'左键拖动按钮移动
If (moves = True And e.Button = Windows.Forms.MouseButtons.Left) Then
'获取实施坐标,更新坐标呢
Dim px = Cursor.Position.X - pt.X
Dim py = Cursor.Position.Y - pt.Y
sender.location = New Point(sender.Location.X + px, sender.Location.Y + py)
pt = Cursor.Position
End If
End Sub
'停止拖动按钮
Sub btn_MouseUp(sender As Object, e As MouseEventArgs)
sender.BringToFront()
If e.Button = Windows.Forms.MouseButtons.Right Then
Return
End If
'计算鼠标的Panel中的相对临时位置,鼠标一般都会处在按钮的中间位置。
Dim p As Point = sender.Location
p.X = sender.Location.X + sender.Width / 2
p.Y = sender.Location.Y + sender.Height / 2
'判断该鼠标位置在那个对应的RectangleShape中
Dim rs As RectangleShape = GetRectangleShape(p)
If (IsNothing(rs)) Then
Return
End If
'拖拽完毕之后
sender.Location = rs.Location
sender.size = New Size(rs.Size.Width + 1, rs.Size.Height + 1)
moves = False
'如果移动的位置有按钮,
ExchangeBtn(sender, sender.Parent) '交换按钮
sender.Tag = rs.Name.Substring(5, 2)
moves = False
End Sub
'交换按钮
Private Function ExchangeBtn(ByVal ptbNew As Button, ByVal panel1 As Panel)
For Each control As Object In panel1.Controls
'判断是否为按钮
If control.GetType().ToString() = "System.Windows.Forms.Button" Then
If ptbNew.Equals(control) = False And ptbNew.Location = control.Location Then
control.Location = ps '移动按钮B到按钮A的原位置
control.Tag = ptbNew.Tag '按钮B被迫更改成按钮A的位置标记
Exit Function
End If
End If
Next
End Function
'返回矩形框的位置
Public Function GetRectangleShape(ByVal point As Point) As RectangleShape
'遍历容器中的矩形框
For Each VARIABLE As Object In canvas.Shapes
'如果当前鼠标指向该矩形框,则将按钮放入矩形框所在的位置
Dim rs As RectangleShape = CType(VARIABLE, RectangleShape)
If (point.X > rs.Left And point.X < rs.Left + rs.Width And point.Y > rs.Top And point.Y < rs.Top + rs.Height) Then
Return rs
End If
Next
Return Nothing
End Function
'右击删除
Private Sub DeleteToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles DeleteToolStripMenuItem.Click
btn.Parent.Controls.Remove(btn)
End Sub
Private Sub ClearToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ClearToolStripMenuItem.Click
Dim panel = btn.Parent
'遍历本地个性化设置中的控件
For index = panel.Controls.Count - 1 To 0 Step -1
If panel.Controls(index).GetType().ToString() = "System.Windows.Forms.Button" Then
panel.Controls.Remove(panel.Controls(index))
End If
Next
End Sub
End Class
注意:
Private SubForm1_DragEnter(sender As Object, e As DragEventArgs) HandlesMyBase.DragEnter, Panel1.DragEnter, Button1.DragEnter
If (e.Data.GetDataPresent(GetType(Button)))Then
e.Effect = DragDropEffects.Move
End If
End Sub
这里红色部分的MyBase.DragEnter,Panel1.DragEnter, Button1.DragEnter
需要在在控件的事件中设置 Form1_DragEnter的事件,否则就鼠标的效果只能局部有效。
效果图如下:
小结:
这段代码经过二次实现,整理出来的。由于第一次实现的时候,感觉各种乱,心里对代码存在一些恐惧感,然后在米老师的建议下,又重现实现了一遍。但是代码的调试过程中还是存在一些问题,不过当我静下心来分析问题的时候,那些问题再也不是问题了。