【问题标题】:Limit Thumb to elliptic area将拇指限制在椭圆区域
【发布时间】:2012-04-25 17:56:42
【问题描述】:

我对 WPF 很陌生,所以我正在以艰难(但有趣)的方式学习其中的大部分内容。我正在构建一个类似 HSV 的颜色选择器用户控件,并且希望获得我用作“选择器”的拇指仅限于椭圆区域(实际上是圆形)的行为。当移到外面时,选择器应该粘在一边,根本不动。我相信这是最常见的 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 制作的新手,所以也许有一些我没有想到的明显解决方案;)

【问题讨论】:

    标签: c# wpf user-controls slider area


    【解决方案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>
    

    【讨论】:

      【解决方案2】:

      您希望拇指的中心位于色轮内。

      因此,拇指中心与色轮中心(即画布中心)之间的距离必须小于 或等于色轮的半径(即画布边的一半)。

      未经测试的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);
      }
      

      【讨论】:

      • 谢谢,虽然当光标在外面时它不会固定在边缘不动,但你肯定做了很大的工作!如果光标离开并重新进入,拇指和光标也会分开,所以我会做一些调试并接受你的答案。完成后将发布我的最终解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      相关资源
      最近更新 更多