2

我对 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 制作的新手,所以也许有一些我没有想到的明显解决方案;)

4

2 回答 2

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>
于 2012-04-17T12:06:23.863 回答
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);
}
于 2012-04-13T11:42:14.813 回答