2009-07-31 6 views
0

"TableLayoutPanel2"に含まれる "FollowTableLayoutPanel1"の行に一連のコントロールがあります。マウスカーソルの位置に合わせてサイズを変更しました。マウスカーソルがコントロールの垂直中心に近いほど、コントロールは大きくなります。 FollowTableLayoutPanel1のアンカープロパティは "Top"に設定されているため、TableLayoutPanel2で自身を更新します。マウスの位置に応じてコントロールのサイズを変更する際にコントロールの「ぐらつき」を回避しようとしています

これが問題の原因です。 最近のFollowTableLayoutPanel1では、コントロールをマウスポインタから遠くに1ピクセル移動させるとコントロールが縮小し、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

うん。それをやって。 1つのフレームの再配置と次のフレームの再配置の間に発生する副作用を防ぐ方法に関するアイデアが必要です。 – Frosty840

+0

レイアウトを使用しないでください。その代わりに、手動でコントロールを配置し、効果を適用するときに座標を調整します。 – AlexEzh

+0

はい、でも、それを行っても、計算が行われても、*望ましくないウォブル効果が生成されます。 – Frosty840

関連する問題