代码之家  ›  专栏  ›  技术社区  ›  Adam Harte

在WPF中向鼠标方向旋转图形(类似于模拟拨号盘)

  •  9
  • Adam Harte  · 技术社区  · 17 年前

    模拟音量旋钮 ).我希望能够点击并拖动拨号盘,它会随着鼠标旋转。然后,当我释放鼠标时,它将停止跟随(很明显!)。

    3 回复  |  直到 17 年前
        1
  •  23
  •   Nicholas Armstrong    17 年前

    <UserControl x:Class="VolumeControlLibrary.VolumeControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:VolumeControlLibrary"
                 Height="60" Width="60">
        <Image Source="/VolumeControl;component/knob.png" RenderTransformOrigin="0.5,0.5" >
            <Image.RenderTransform>
                <RotateTransform Angle="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:VolumeControl}}, Path=Angle}"/>
            </Image.RenderTransform>
        </Image>
    </UserControl>
    

    将RenderTransformOrigin设置为“0.5,0.5”可确保控件围绕其中心旋转,而不是围绕左上角旋转;我们也必须在角度计算中对此进行补偿。

    在控件的代码隐藏文件中,添加鼠标和Angle DependencyProperty的处理程序:

    public partial class VolumeControl : UserControl
    {
        // Using a DependencyProperty backing store for Angle.
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(VolumeControl), new UIPropertyMetadata(0.0));
    
        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }
    
        public VolumeControl()
        {
            InitializeComponent();
            this.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
            this.MouseUp += new MouseButtonEventHandler(OnMouseUp);
            this.MouseMove += new MouseEventHandler(OnMouseMove);
        }
    
        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Mouse.Capture(this);
        }
    
        private void OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            Mouse.Capture(null);
        }
    
        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (Mouse.Captured == this)
            {
                // Get the current mouse position relative to the volume control
                Point currentLocation = Mouse.GetPosition(this);
    
                // We want to rotate around the center of the knob, not the top corner
                Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);
    
                // Calculate an angle
                double radians = Math.Atan((currentLocation.Y - knobCenter.Y) / 
                                           (currentLocation.X - knobCenter.X));
                this.Angle = radians * 180 / Math.PI;
    
                // Apply a 180 degree shift when X is negative so that we can rotate
                // all of the way around
                if (currentLocation.X - knobCenter.X < 0)
                {
                    this.Angle += 180;
                }
            }
        }
    }
    

    在这个例子中,当鼠标移动时,我们计算它与控件中心之间的角度,然后将此角度设置为我们创建的angle DependencyProperty。由于我们显示的图像绑定到这个角度属性,WPF会自动应用新值,这会导致旋钮随着鼠标的移动而旋转。

    <local:VolumeControl />
    

        2
  •  3
  •   Ron Warholic    17 年前

    要添加到该帖子中,鼠标点和对象点之间的角度计算如下:

    dot = currentLocation.X * objectPosition.X + currentLocation.Y * objectPosition.Y;
    angle = Math.Acos(dot);
    
        3
  •  0
  •   troYman    10 年前

    在我的例子中,我动态创建了将向鼠标方向旋转的形状。为了解决这个问题,我使用了一个轻量级函数。我只需要以下内容:

    • 以及当前鼠标悬停步骤的点

    不必使用Math库中的方法。我计算的角度取决于当前鼠标悬停点和前一个鼠标悬停点的差异以及相对于中心点的位置。最后,我在当前对象的现有角度上添加角度。

    private void HandleLeftMouseDown(MouseButtonEventArgs eventargs)
    {
        //Calculate the center point of selected object
        //...
        //assuming Point1 is the top left point
        var xCenter = (_selectedObject.Point2.X - _selectedObject.Point1.X) / 2 + _selectedObject.Point1.X
        var yCenter = (_selectedObject.Point2.Y - _selectedObject.Point1.Y) / 2 + _selectedObject.Point1.Y
        _selectedObjectCenterPoint = new Point((double) xCenter, (double) yCenter);
    
        //init set of last mouse over step with the mouse click point
         var clickPoint = eventargs.GetPosition(source);
        _lastMouseOverPoint = new Point(clickPoint.X,clickPoint.Y);
    }
    
    private void HandleMouseMove(MouseEventArgs eventArgs)
    {
        Point pointMouseOver = eventArgs.GetPosition(_source);                            
    
        //Get the difference to the last mouse over point
        var xd = pointMouseOver.X - _lastMouseOverPoint.X;
        var yd = pointMouseOver.Y - _lastMouseOverPoint.Y;
    
        // the direction depends on the current mouse over position in relation to the center point of the shape
        if (pointMouseOver.X < _selectedObjectCenterPoint.X)
            yd *= -1;
        if (pointMouseOver.Y > _selectedObjectCenterPoint.Y)
            xd *= -1;
    
        //add to the existing Angle   
        //not necessary to calculate the degree measure
        _selectedObject.Angle += (xd + yd);
    
        //save mouse over point            
        _lastMouseOverPoint = new Point(pointMouseOver.X, pointMouseOver.Y);
    }