2012-04-13 57 views
2

我對WPF很新,所以我正在學習這個艱難(但有趣)的方式。我正在構建一個類似HSV的colorPicker usercontrol,並希望獲得這種行爲,因爲「選擇器」僅限於橢圓區域(實際上是圓形),所以我使用的是拇指。當移到外面時,選擇器應該靠在一邊而不能移動。我相信這是最常見的GUI行爲,所以這就是它的行爲。隨意建議一個更好的行爲!限制拇指橢圓區域

是否有一個共同的,已知的和推薦的解決方案呢,還是每個人都需要每次重新發明車輪?

如何解決這個問題的好主意?

代碼隱藏:

public partial class HSVColorPicker : UserControl 
{ 
    public HSVColorPicker() 
    { 
     InitializeComponent(); 
    } 

    void onDragDelta(object sender, DragDeltaEventArgs e) 
    { 
     Canvas.SetLeft(thumb, Canvas.GetLeft(thumb) + e.HorizontalChange); 
     Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange); 
    } 
} 

XAML:

<Grid> 
    <Canvas x:Name="canvas"> 
     <Image x:Name="wheel" Source="colorwheel.png" Width="300" Margin="5,5,0,0"/> 
     <Thumb Name="thumb" DragDelta="onDragDelta" Canvas.Left="104" Canvas.Top="68" Template="{StaticResource thumbTemplate}" /> 
    </Canvas> 
</Grid> 

雖然我在這裏,大拇指總是拖動光標背後,有另一種方式來創建這個?正如我所說,我是新來的WPF和GUI製作,所以也許有明顯的解決方案,我沒有想到;)

回答

1

我做了一些重新思考和徹底放棄了大拇指,使用虛擬圓(命名爲拇指)來代替。現在我正在監聽,mousedown,mouseup和mousemove在畫布上,並確定什麼是可能的,而不是。這有一個很好的功能,當鼠標移動到區域外時,拇指粘在色輪邊緣上,但該區域比色輪稍大,以便輕鬆獲得邊界上的點。不完整,但它解決了我的問題,所以我現在就發佈它。

private bool mousePressed { get; set; } 
    private bool mouseWithinArea { get; set; } 
    private Point circleMiddlePoint { get; set; } 
    private int margin; 
    private double mPX; 
    private double mPY; 
    private double localXpos; 
    private double globalXpos 
    { 
     get 
     { 
      return localXpos + mPX; 
     } 
     set 
     { 
      localXpos = value - mPX; 
      Canvas.SetLeft(thumb, value); 
     } 
    } 
    private double localYpos; 
    private double globalYpos 
    { 
     get 
     { 
      return mPY - localYpos; 
     } 
     set 
     { 
      localYpos = mPY - value; 
      Canvas.SetTop(thumb, value); 
     } 
    } 

    public HSVColorPicker() 
    { 
     InitializeComponent(); 
     wheel.Width = 300; 
     margin = 15; 
     mPX = 150+margin; 
     mPY = 150+margin; 
     circleMiddlePoint = new Point(mPX, mPY); 
    } 

    private void CalcPosition(double X, double Y) 
    { 
     double radius = wheel.Width/2.0; 
     double vectorX = X - mPX; 
     double vectorY = Y - mPY; 
     double distance = Math.Sqrt(vectorX * vectorX + vectorY * vectorY); 
     if (distance > radius) 
     { 
      double factor = radius/distance; 
      vectorX *= factor; 
      vectorY *= factor; 
     } 
     globalXpos = vectorX + mPX; 
     globalYpos = vectorY + mPY; 
    } 

    private void wheel_MouseDown(object sender, MouseButtonEventArgs e) 
    { 
     if (mouseWithinArea) 
     { 
      mousePressed = true; 
      Point mousePoint = e.GetPosition(this); 
      CalcPosition(mousePoint.X, mousePoint.Y); 
     } 
    } 

    private void wheel_MouseMove(object sender, MouseEventArgs e) 
    { 
     Point mousePoint = e.GetPosition(this); 
     double relX = mousePoint.X - mPX; 
     double relY = mPY - mousePoint.Y; 
     if (mouseWithinArea) 
     { 
      if (Math.Sqrt(relX * relX + relY * relY) > 150+margin) 
      { 
       mouseWithinArea = false; 
      } 
      else 
      { 
       if (mousePressed) 
       { 
        CalcPosition(mousePoint.X, mousePoint.Y); 
       } 
      } 
     } 
     else 
     { 
      if (Math.Sqrt(relX * relX + relY * relY) < 150+margin) 
      { 
       mouseWithinArea = true; 
       if (mousePressed) 
       { 
        CalcPosition(mousePoint.X, mousePoint.Y); 
       } 
      } 
     } 
    } 

    private void wheel_MouseUp(object sender, MouseButtonEventArgs e) 
    { 
     mousePressed = false; 
    } 
} 

<Canvas x:Name="canvas" Background="Transparent" MouseDown="wheel_MouseDown" MouseMove="wheel_MouseMove" MouseUp="wheel_MouseUp" Width="330" Height="330"> 
     <Image x:Name="wheel" Source="colorwheel.png" Width="300" Margin="15,15,0,0" /> 
     <Ellipse Margin="0,0,0,0" 
       x:Name="outerEll" 
       Stroke="Silver" 
       StrokeThickness="15" 
       Width="330" 
       Height="330"/> 
     <Ellipse Name="thumb" Stroke="Black" Fill="Silver" Canvas.Left="150" Canvas.Top="150" Width="15" Height="15" Margin="-12" /> 
    </Canvas> 
0

你想拇指的中心位於你的色輪。

因此,拇指中心與色輪中心之間的距離(即畫布中心)必須小於 或等於色輪的半徑(即一半畫布的一側)。

未經測試的C#代碼:

void onDragDelta(object sender, DragDeltaEventArgs e) 
{ 
    double radius = canvas.RenderSize.Width/2.0; 
    double thumbCenterX = Canvas.GetLeft(thumb) - thumb.RenderSize.Width + e.HorizontalChange; 
    double thumbCenterY = Canvas.GetTop(thumb) - thumb.RenderSize.Height + e.VerticalChange; 
    double colorWheelCenterX = canvas.RenderSize.Width/2.0; 
    double colorWheelCenterY = canvas.RenderSize.Height/2.0; 
    double vectorX = thumbCenterX - colorWheelCenterX; 
    double vectorY = thumbCenterY - colorWheelCenterY; 
    double distance = Math.Sqrt(vectorX * vectorX + vectorY * vectorY); 
    if(distance > radius) { 
     double factor = radius/distance; 
     vectorX *= factor; 
     vectorY *= factor; 
    } 
    Canvas.SetLeft(thumb, colorWheelCenterX + vectorX - thumb.RenderSize.Width/2.0); 
    Canvas.SetTop(thumb, colorWheelCenterY + vectorY - thumb.RenderSize.Height/2.0); 
} 
+0

謝謝,雖然它不會在光標在外邊不動,但你確實做了很大一部分工作!如果光標離開並重新進入,拇指和光標也會分開,所以我會進行一些調試並接受您的答案。完成後會發布我的最終解決方案。 – Bob 2012-04-14 11:29:35