2012-04-13 54 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