我在“FollowTableLayoutPanel1”中的一行中有一组控件,包含在“TableLayoutPanel2”中。我根据鼠标光标的位置调整大小;鼠标光标越靠近控件的垂直中心,控件越大。因为FollowTableLayoutPanel1的anchor属性设置为“Top”,所以它最近在TableLayoutPanel2中显示。
这就是我遇到问题的地方。 FollowTableLayoutPanel1的recentring可以将控件移动一个像素远离鼠标指针,这会导致控件缩小,从而导致FollowTableLayoutPanel1最近,将控件放置得更接近鼠标指针,从而导致控件增长,这会导致FollowTableLayoutPanel1到recentre,这会使控件进一步远离鼠标光标等,等等。 最终的结果是整个设置抖动和摆动,不断调整大小。
任何人都可以提出一种方法来抑制这种颤抖吗?
下面提供了完整的示例代码,可以直接粘贴到新项目的Form1中。定位鼠标光标以正确显示问题留给读者练习:P
Public Class Form1
Private Sub myInitializeComponent()
Me.components = New System.ComponentModel.Container
Me.TableLayoutPanel2 = New System.Windows.Forms.TableLayoutPanel
Me.FollowTableLayoutPanel1 = New FollowTableLayoutPanel
Me.Button9 = New System.Windows.Forms.Button
Me.Button8 = New System.Windows.Forms.Button
Me.Button7 = New System.Windows.Forms.Button
Me.Button6 = New System.Windows.Forms.Button
Me.Button5 = New System.Windows.Forms.Button
Me.Button3 = New System.Windows.Forms.Button
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Button4 = New System.Windows.Forms.Button
Me.TableLayoutPanel2.SuspendLayout()
Me.FollowTableLayoutPanel1.SuspendLayout()
Me.SuspendLayout()
'
'TableLayoutPanel2
'
Me.TableLayoutPanel2.ColumnCount = 1
Me.TableLayoutPanel2.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
Me.TableLayoutPanel2.Controls.Add(Me.FollowTableLayoutPanel1, 0, 0)
Me.TableLayoutPanel2.Location = New System.Drawing.Point(12, 115)
Me.TableLayoutPanel2.Name = "TableLayoutPanel2"
Me.TableLayoutPanel2.RowCount = 1
Me.TableLayoutPanel2.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
Me.TableLayoutPanel2.Size = New System.Drawing.Size(1194, 341)
Me.TableLayoutPanel2.TabIndex = 2
'
'FollowTableLayoutPanel1
'
Me.FollowTableLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.FollowTableLayoutPanel1.AutoSize = True
Me.FollowTableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink
Me.FollowTableLayoutPanel1.ColumnCount = 9
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button9, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button8, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button7, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button6, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button5, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button3, 2, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button1, 0, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button2, 1, 0)
Me.FollowTableLayoutPanel1.Controls.Add(Me.Button4, 3, 0)
Me.FollowTableLayoutPanel1.Location = New System.Drawing.Point(259, 0)
Me.FollowTableLayoutPanel1.Margin = New System.Windows.Forms.Padding(0)
Me.FollowTableLayoutPanel1.Name = "FollowTableLayoutPanel1"
Me.FollowTableLayoutPanel1.RowCount = 1
Me.FollowTableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle)
Me.FollowTableLayoutPanel1.Size = New System.Drawing.Size(675, 50)
Me.FollowTableLayoutPanel1.TabIndex = 1
Me.FollowTableLayoutPanel1.Text = "{X=0,Y=0}" & Global.Microsoft.VisualBasic.ChrW(9) & Global.Microsoft.VisualBasic.ChrW(9) & "00:00:00.0090009"
'
'Button9
'
Me.Button9.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button9.Location = New System.Drawing.Point(225, 0)
Me.Button9.Margin = New System.Windows.Forms.Padding(0)
Me.Button9.Name = "Button9"
Me.Button9.Size = New System.Drawing.Size(75, 50)
Me.Button9.TabIndex = 5
Me.Button9.Text = "{Width=75, Height=50}"
Me.Button9.UseVisualStyleBackColor = True
'
'Button8
'
Me.Button8.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button8.Location = New System.Drawing.Point(300, 0)
Me.Button8.Margin = New System.Windows.Forms.Padding(0)
Me.Button8.Name = "Button8"
Me.Button8.Size = New System.Drawing.Size(75, 50)
Me.Button8.TabIndex = 4
Me.Button8.Text = "{Width=75, Height=50}"
Me.Button8.UseVisualStyleBackColor = True
'
'Button7
'
Me.Button7.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button7.Location = New System.Drawing.Point(375, 0)
Me.Button7.Margin = New System.Windows.Forms.Padding(0)
Me.Button7.Name = "Button7"
Me.Button7.Size = New System.Drawing.Size(75, 50)
Me.Button7.TabIndex = 3
Me.Button7.Text = "{Width=75, Height=50}"
Me.Button7.UseVisualStyleBackColor = True
'
'Button6
'
Me.Button6.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button6.Location = New System.Drawing.Point(0, 0)
Me.Button6.Margin = New System.Windows.Forms.Padding(0)
Me.Button6.Name = "Button6"
Me.Button6.Size = New System.Drawing.Size(75, 50)
Me.Button6.TabIndex = 2
Me.Button6.Text = "{Width=75, Height=50}"
Me.Button6.UseVisualStyleBackColor = True
'
'Button5
'
Me.Button5.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button5.Location = New System.Drawing.Point(75, 0)
Me.Button5.Margin = New System.Windows.Forms.Padding(0)
Me.Button5.Name = "Button5"
Me.Button5.Size = New System.Drawing.Size(75, 50)
Me.Button5.TabIndex = 1
Me.Button5.Text = "{Width=75, Height=50}"
Me.Button5.UseVisualStyleBackColor = True
'
'Button3
'
Me.Button3.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button3.Location = New System.Drawing.Point(525, 0)
Me.Button3.Margin = New System.Windows.Forms.Padding(0)
Me.Button3.Name = "Button3"
Me.Button3.Size = New System.Drawing.Size(75, 50)
Me.Button3.TabIndex = 0
Me.Button3.Text = "{Width=75, Height=50}"
Me.Button3.UseVisualStyleBackColor = True
'
'Button1
'
Me.Button1.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button1.Location = New System.Drawing.Point(150, 0)
Me.Button1.Margin = New System.Windows.Forms.Padding(0)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(75, 50)
Me.Button1.TabIndex = 0
Me.Button1.Text = "{Width=75, Height=50}"
Me.Button1.UseVisualStyleBackColor = True
'
'Button2
'
Me.Button2.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button2.Location = New System.Drawing.Point(450, 0)
Me.Button2.Margin = New System.Windows.Forms.Padding(0)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(75, 50)
Me.Button2.TabIndex = 0
Me.Button2.Text = "{Width=75, Height=50}"
Me.Button2.UseVisualStyleBackColor = True
'
'Button4
'
Me.Button4.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.Button4.Location = New System.Drawing.Point(600, 0)
Me.Button4.Margin = New System.Windows.Forms.Padding(0)
Me.Button4.Name = "Button4"
Me.Button4.Size = New System.Drawing.Size(75, 50)
Me.Button4.TabIndex = 0
Me.Button4.Text = "{Width=75, Height=50}"
Me.Button4.UseVisualStyleBackColor = True
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(1218, 577)
Me.Controls.Add(Me.TableLayoutPanel2)
Me.Name = "Form1"
Me.Text = "Form1"
Me.TableLayoutPanel2.ResumeLayout(False)
Me.TableLayoutPanel2.PerformLayout()
Me.FollowTableLayoutPanel1.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Button3 As System.Windows.Forms.Button
Friend WithEvents Button4 As System.Windows.Forms.Button
Friend WithEvents FollowTableLayoutPanel1 As FollowTableLayoutPanel
Friend WithEvents TableLayoutPanel2 As System.Windows.Forms.TableLayoutPanel
Friend WithEvents Button9 As System.Windows.Forms.Button
Friend WithEvents Button8 As System.Windows.Forms.Button
Friend WithEvents Button7 As System.Windows.Forms.Button
Friend WithEvents Button6 As System.Windows.Forms.Button
Friend WithEvents Button5 As System.Windows.Forms.Button
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
myInitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Private Sub FollowTableLayoutPanel1_TimerTick() Handles FollowTableLayoutPanel1.TimerTick
Me.Text = Me.FollowTableLayoutPanel1.Text
End Sub
Private Sub TableLayoutPanel1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TableLayoutPanel2.MouseMove
Me.FollowTableLayoutPanel1.parentMouseMove(e.Location)
End Sub
Private Sub TableLayoutPanel1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles TableLayoutPanel2.MouseLeave
Me.FollowTableLayoutPanel1.parentMouseLeave()
End Sub
End Class
Public Class FollowTableLayoutPanel
Inherits TableLayoutPanel
Public WithEvents animTimer As Timer
Private Class ControlSize
Private _sizing As Boolean
Private _bigSize As Size
Public ReadOnly Property BigSize() As Size
Get
Return _bigSize
End Get
End Property
Private _smallSize As Size
Public ReadOnly Property SmallSize() As Size
Get
Return _smallSize
End Get
End Property
Private WithEvents _thisControl As Control
Public ReadOnly Property ThisControl() As Control
Get
Return _thisControl
End Get
End Property
Public Sub New(ByVal thisControl As Control)
Me._sizing = False
Me._thisControl = thisControl
Me._bigSize = New Size(thisControl.Width * 2, thisControl.Height * 2)
Me._smallSize = thisControl.Size
End Sub
Public Sub Resize(ByVal sizeTo As Size)
Me._sizing = True
Me._thisControl.Size = sizeTo
Me._sizing = False
End Sub
Private Sub _thisControl_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _thisControl.SizeChanged
If Not Me._sizing Then
Me._bigSize = New Size(ThisControl.Width * 2, ThisControl.Height * 2)
Me._smallSize = ThisControl.Size
End If
End Sub
End Class
Private sizeDict As List(Of ControlSize)
Public Sub New()
MyBase.New()
Me.sizeDict = New List(Of ControlSize)
Me.DoubleBuffered = True
Me.animTimer = New Timer()
Me.animTimer.Interval = 10
Me.animTimer.Start()
End Sub
Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
MyBase.OnControlAdded(e)
e.Control.Text = String.Empty
sizeDict.Add(New ControlSize(e.Control))
AddHandler e.Control.MouseMove, AddressOf ControlIn_MouseMove
AddHandler e.Control.MouseLeave, AddressOf ControlIn_MouseLeave
End Sub
Protected Overrides Sub OnControlRemoved(ByVal e As System.Windows.Forms.ControlEventArgs)
MyBase.OnControlRemoved(e)
For Each controlSizeIn As ControlSize In Me.sizeDict
If controlSizeIn.ThisControl Is e.Control Then
sizeDict.Remove(controlSizeIn)
Exit For
End If
Next
RemoveHandler e.Control.MouseMove, AddressOf ControlIn_MouseMove
RemoveHandler e.Control.MouseLeave, AddressOf ControlIn_MouseLeave
End Sub
Public Event TimerTick()
Private Sub animTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles animTimer.Tick
Me.SuspendLayout()
moveButton()
Me.PerformLayout()
Me.ResumeLayout()
RaiseEvent TimerTick()
End Sub
Private Sub moveButton()
Static lastTime As Long = DateTime.Now.Ticks
If mouseLocation.X <> 0 Then
For Each csIn As ControlSize In Me.sizeDict
Dim controlIn As Control = csIn.ThisControl
Dim controlCentrePoint As New Point(CInt(controlIn.Left + (controlIn.Width / 2)), CInt(controlIn.Top + (controlIn.Height / 2)))
Dim differenceX As Integer = Math.Abs(controlCentrePoint.X - mouseLocation.X)
Dim setDifferenceX As Integer = csIn.BigSize.Width - differenceX
Dim setTargetX As Integer = If(setDifferenceX < csIn.SmallSize.Width, csIn.SmallSize.Width, setDifferenceX)
Dim targetChangeX As Integer = CInt((Math.Abs(setTargetX - controlIn.Width)) / 5)
Dim setChangeX As Integer = If(targetChangeX = 0, 1, targetChangeX)
If setTargetX < controlIn.Width AndAlso controlIn.Width <= csIn.BigSize.Width Then
Dim setX As Integer = controlIn.Width - setChangeX
csIn.Resize(New Size(setX, CInt(csIn.SmallSize.Height * (setX / csIn.SmallSize.Width))))
ElseIf setTargetX > controlIn.Width AndAlso controlIn.Width >= csIn.SmallSize.Width Then
Dim setX As Integer = controlIn.Width + setChangeX
csIn.Resize(New Size(setX, CInt(csIn.SmallSize.Height * (setX / csIn.SmallSize.Width))))
End If
controlIn.Text = controlIn.Size.ToString
Next
Else
For Each csIn As ControlSize In Me.sizeDict
Dim controlIn As Control = csIn.ThisControl
If csIn.SmallSize.Width < controlIn.Width AndAlso controlIn.Width <= csIn.BigSize.Width Then
Dim targetChangeX As Integer = CInt((Math.Abs(csIn.SmallSize.Width - controlIn.Width)) / 5)
Dim setChangeX As Integer = If(targetChangeX = 0, 1, targetChangeX)
Dim setX As Integer = controlIn.Width - setChangeX
Dim setY As Integer = CInt(csIn.SmallSize.Height * (setX / csIn.SmallSize.Width))
csIn.Resize(New Size(setX, setY))
End If
controlIn.Text = controlIn.Size.ToString
Next
End If
Dim nowTicks As Long = DateTime.Now.Ticks
Dim ts As New TimeSpan(nowTicks - lastTime)
lastTime = nowTicks
Me.Text = Me.mouseLocation.ToString & vbTab & vbTab & ts.ToString
End Sub
Private mouseLocation As Point
Private Sub Form1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
mouseLocation = New Point(0, 0)
End Sub
Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
mouseLocation = e.Location
End Sub
Private Sub ControlIn_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
mouseLocation = New Point(CInt(e.X + CType(sender, Control).Left), CInt(e.Y + CType(sender, Control).Top))
End Sub
Private Sub ControlIn_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs)
mouseLocation = New Point(0, 0)
End Sub
Public Sub parentMouseMove(ByVal mouseCoordinates As Point)
mouseLocation = New Point(mouseCoordinates.X - Me.Left, mouseCoordinates.Y - Me.Top)
End Sub
Public Sub parentMouseLeave()
mouseLocation = New Point(0, 0)
End Sub
End Class
答案 0 :(得分:1)
您是否尝试实施类似于OSX中的底座的鱼眼效果?不要在每个单独的控件级别上处理鼠标事件,而是尝试在父级别上处理鼠标。当父级接收鼠标移动时,计算所有控件的新位置并进行调整。
我一直在使用以下方法来计算鱼眼效应的位置。基本上,这个想法是根据鼠标的位置来缩放/移动元素。 pt是鼠标的坐标。 target.Pos是未缩放的坐标。 ScaledPos是新的缩放坐标
double dx = target.Pos.X + target.Pos.Width / 2 - pt.X;
double scale = DistanceToScale(Math.Sqrt(dx * dx + dy * dy));
double xRel = pt.X - target.Pos.X;
double dxTarget = xRel * scale - xRel;
target.ScaledPos = new Rect(target.Pos.X - dxTarget,
target.Pos.Y,
target.Pos.Width * scale,
target.Pos.Height);
您必须计算所有元素的位置。 DistanceToScale函数定义比例从最大比例(当鼠标位于元素顶部时)到1(项目未缩放)的快速变化。功能应该是平滑的,以避免跳跃。
double DistanceToScale(double distance)
{
double dblScale = _c1 / (1.0 + (distance * distance * _c2));
if (dblScale < 1.0)
{
dblScale = 1.0;
}
return dblScale;
}
其中c1和c2
_c1 = maximun_scale;
_c2 = (c1 / scale_at_distance_dx) - 1 / (dx ^ 2);