2009-06-07 30 views
7

在WPF/C#中,我將如何旋轉「圖形」以面對當前鼠標位置?向WPF中的鼠標旋轉圖形(如模擬撥號)

基本上我想要的是一個「輪」UI控制(如模擬量撥號)。我希望能夠點擊並拖動撥號,並且它會旋轉以跟隨鼠標。然後當我釋放鼠標時,它會停止(顯然!)。

我將如何創建其中之一?某個地方是否已經存在?

回答

19

我還沒有看到過這樣的控件(雖然從我看過WPF控件供應商提供的所有控件已經有一段時間了),但創建一個控件相對比較簡單。

您只需創建一個包含圖像(或XAML圖形)的自定義控件,該圖像可以旋轉以跟隨鼠標。然後,RotateTransform結合於自定義控制的「角度」的DependencyProperty以便當「角度」被更新時,圖像/繪圖旋轉以匹配:

<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」確保了控制圍繞其中心旋轉,而不是圍繞左上角旋轉;我們也必須在角度計算中進行補償。

在隱藏文件的控制代碼,添加處理程序的鼠標和角度的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; 
      } 
     } 
    } 
} 

捕獲鼠標確保您的控制將繼續得到鼠標的更新甚至當用戶將鼠標關閉的(直到他們放開了點擊),並且通過獲取鼠標相對於當前元素(控件)的位置,無論控件在屏幕上實際呈現的位置如何,您的計算總是應該相同。

在本例中,當鼠標移動時,我們計算它與控件中心之間的角度,然後將此角度設置爲我們創建的角度依賴屬性。由於我們正在顯示的圖像被綁定到這個角度屬性,因此WPF會自動應用新值,這會導致旋鈕與鼠標移動結合在一起旋轉。

在解決方案中使用控件非常簡單;只需添加:

<local:VolumeControl /> 

如果你想旋鈕的值綁定到應用程序中的東西,你會綁定到volume control還Angle屬性;該值目前以度爲單位,但可以添加一個額外的屬性,以角度(以度爲單位)和對您有意義的值(例如0-10的值)之間進行轉換。

+0

我不能完全弄清楚把每一位代碼放在哪裏。我特別在獲取DependencyProperty部分時遇到問題。 – 2009-06-08 04:31:50

3

要添加到該柱中,鼠標點和目標點之間的角度,計算等:

dot = currentLocation.X * objectPosition.X + currentLocation.Y * objectPosition.Y; 
angle = Math.Acos(dot); 
0

在我的情況我已經動態創建其中應朝向鼠標方向旋轉的形狀。爲了解決這個問題,我使用了輕量級功能所有我需要的是以下幾點:

  • 當前選中的形狀
  • 從上次鼠標懸停一步
  • ,並從當前鼠標懸停步

點的點的中心點沒有必要使用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); 
}