将拇指限制为椭圆区域

时间:2012-04-13 11:04:07

标签: c# wpf user-controls slider area

我对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制作的新手,所以也许有明显的解决方案没有发生在我身上;)

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分: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);
}