2009-07-31 1 views
0

"TableLayoutPanel2"에 포함 된 "FollowTableLayoutPanel1"안의 한 줄에 컨트롤 집합이 있습니다. 마우스 커서의 위치에 따라 크기가 조정됩니다. 마우스 커서가 컨트롤의 수직 중심에 가까울수록 컨트롤이 커집니다. FollowTableLayoutPanel1의 앵커 속성이 "Top"으로 설정되어 있으므로 TableLayoutPanel2에서 자체적으로 자체 수정됩니다.마우스 위치에 따라 컨트롤의 크기를 조정할 때 컨트롤 "흔들림"을 피하려고 시도합니다.

이것이 내가 문제가되는 곳입니다. 최근 FollowTableLayoutPanel1에서 컨트롤을 마우스 포인터에서 한 픽셀 더 멀리 이동하면 컨트롤이 축소되어 FollowTableLayoutPanel1이 recentre이되고 컨트롤을 마우스 포인터에 더 가깝게 배치하여 컨트롤이 커지게 할 수 있습니다 이것은 마우스 커서 등으로부터 멀리 떨어져 컨트롤을 이동시키는 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 

답변

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); 
+0

그래. 그러는거야. 한 프레임의 위치 변경과 다음 프레임 사이의 부작용을 방지하는 방법에 대한 아이디어가 필요합니다. – Frosty840

+0

레이아웃을 사용하지 마십시오. 대신 원하는 위치에서 수동으로 위치를 지정하고 효과를 적용 할 때 좌표를 조정하십시오. – AlexEzh

+0

예, 그렇다고해도 계산이 완료되면 원치 않는 워블 효과가 생성됩니다. – Frosty840

관련 문제