2010-11-04 22 views
5

Bir Wpf Uygulaması yapıyorum ve bir göz şekli ile bir Kontrol yaratıyorum, bir Tuval'e Ellipse (göz) koydum ve amacım, fare imlecinin girmesidir. Tuvalde Elips, fare imlecini takip eder. Bu görevi nasıl gerçekleştireceğiniz konusunda herhangi bir öneriniz var mı? İlginiz için çok teşekkürler.Nesne farenin imlecini takip edin

Alkış

DÜZENLEME

Ben Xaml kodumu güncelleme vardır:

<Window Height="480" Title="Window2" Width="640" x:Class="WpfApplication5.Window2" 
    x:Name="Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Window.Resources> 
    <Storyboard x:Key="OnLoaded1"> 
     <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
     Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"> 
     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"> 
      <EasingDoubleKeyFrame.EasingFunction> 
      <ExponentialEase EasingMode="EaseOut" /> 
      </EasingDoubleKeyFrame.EasingFunction> 
     </EasingDoubleKeyFrame> 
     </DoubleAnimationUsingKeyFrames> 
     <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
      Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"> 
     <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"> 
     <EasingDoubleKeyFrame.EasingFunction> 
      <ExponentialEase EasingMode="EaseOut" /> 
      </EasingDoubleKeyFrame.EasingFunction> 
     </EasingDoubleKeyFrame> 
     </DoubleAnimationUsingKeyFrames> 
    </Storyboard> 
    <Style TargetType="Ellipse"> 
     <Setter Property="RenderTransform"> 
     <Setter.Value> 
      <ScaleTransform ScaleX="1" ScaleY="1"/> 
     </Setter.Value> 
     </Setter> 
     <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/> 
    </Style> 
    </Window.Resources> 

    <Canvas MouseMove="mov" x:Name="LayoutRoot"> 
    <Border ackground="Black" B="" Canvas.Left="178" Canvas.Top="103" 
     CornerRadius="250" Height="255.5" Width="290" x:Name="border_eye"> 
     <Ellipse Fill="#FFFFC600" Height="12" HorizontalAlignment="Left" 
     Margin="0" RenderTransformOrigin="0.5,0.5" Stroke="{x:Null}" 
     VerticalAlignment="Center" Visibility="Visible" Width="12" x:Name="ctrCircle"> 
     <Ellipse.RenderTransform> 
      <TransformGroup> 
      <ScaleTransform /> 
      <SkewTransform /> 
      <RotateTransform /> 
      <TranslateTransform />     
      </TransformGroup> 
     </Ellipse.RenderTransform> 
     </Ellipse> 
    </Border> 
    </Canvas> 
</Window> 

ve arkasında kod: i taşıdığınızda

private void mov(object sender, MouseEventArgs e) 
    { 
System.Windows.Point pt = e.GetPosition((Canvas)sender); 
     Storyboard invokeStoryboard = this.Resources["OnLoaded1"] as Storyboard; 
     ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[0]).KeyFrames[0].Value = pt.X; 
     ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[1]).KeyFrames[0].Value = pt.Y; 
     invokeStoryboard.Begin(); 
    } 

şimdi amacım Tuval alanındaki fare (LayoutRoot) Elips (ctrCircle) yalnızca Sınır (border_eye) içinde hareket eder ve "border_eye" alanının üstesinden gelmeyin bu etki bir göz benzer.

Bu adımı çözmek için herhangi bir girişiniz var mı?

Çok teşekkürler

İyi günler.

Alkış

cevap

7

Rx framework'u kullanarak bir WPF kanvasında gözün nasıl yapılacağına dair bir örnek. Fare hareketine iliştirmek yerine Rx kullanmak, doğrudan olayları tamponlamanıza ve yalnızca toplam CPU yükünü azaltarak her 10 milisaniyede bir Pupil pozisyonunu güncellemenize izin verir.

Xaml

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    x:Class="namespace.EyeDemo" 
    x:Name="UserControl" 
    d:DesignWidth="640" d:DesignHeight="480"> 

    <Canvas x:Name="LayoutRoot" Background="GreenYellow"> 
     <Ellipse Fill="Black" Width="120" Height="70" Canvas.Left="90" Canvas.Top="115"/> 
     <Ellipse x:Name="Eye" Fill="Black" Width="100" Height="50" Canvas.Left="100" Canvas.Top="125"/> 
     <Ellipse x:Name="Pupil" Fill="Red" Height="20" Canvas.Left="139" Canvas.Top="138" Width="20"/> 
    </Canvas> 
</UserControl> 

ve ben bir ayrıntıyı i kodunu yazıp başka bileşende göz kalmak yazmayı unuttum

/// <summary> 
/// Interaction logic for EyeDemo.xaml 
/// </summary> 
public partial class EyeDemo : UserControl 
{ 
    public EyeDemo() 
    { 
     this.InitializeComponent(); 

     double majorRadius = Eye.Width/2d; 
     double minorRadius = Eye.Height/2d; 
     Point center = new Point(Canvas.GetLeft(Eye) + majorRadius, Canvas.GetTop(Eye) + minorRadius); 

     // create event streams for mouse down/up/move using reflection 
     // to keep taking mouse move events and return the X, Y positions 
     var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(LayoutRoot, "PreviewMouseMove") 
         select (Point?)evt.EventArgs.GetPosition(this); 

     // subscribe to the stream of position changes and modify the Canvas.Left and Canvas.Top 
     // use the bound by elipse function to restrain the pupil to with the eye. 
     mouseMove.BufferWithTime(TimeSpan.FromMilliseconds(10)).Select(p => BoundByElipse(majorRadius, minorRadius, center, p.LastOrDefault())) 
      .ObserveOnDispatcher().Subscribe(pos => 
       { 
        if(pos.HasValue) 
        { 
         Canvas.SetLeft(Pupil, pos.Value.X - Pupil.Width/2d); 
         Canvas.SetTop(Pupil, pos.Value.Y - Pupil.Height/2d); 
        } 
       }); 
    } 

    private Point? BoundByElipse(double majorRadius, double minorRadius, Point center, Point? point) 
    { 
     if(point.HasValue) 
     { 
      // Formular for an elipse is x^2/a^2 + y^2/b^2 = 1 
      // where a = majorRadius and b = minorRadius 
      // Using this formular we can work out if the point is with in the elipse 
      // or find the boundry point closest to the point 

      // Find the location of the point relative to the center. 
      Point p = new Point(point.Value.X - center.X, point.Value.Y - center.Y); 
      double a = majorRadius; 
      double b = minorRadius; 

      double f = p.X * p.X/(a * a) + p.Y * p.Y/(b * b); 
      if(f <= 1) 
      { 
       // the point is with in the elipse; 
       return point; 
      } 
      else 
      { 
       // the point is outside the elipse, therefore need to find the closest location on the boundry. 
       double xdirection = point.Value.X > center.X ? 1 : -1; 
       double ydirection = point.Value.X > center.X ? 1 : -1; 

       double r = p.X/p.Y; 

       double x = p.Y != 0 ? Math.Sqrt(r * r * a * a * b * b/(r * r * b * b + a * a)) : a; 
       double y = r != 0 ? x/r : (point.Value.Y > center.Y ? -b : b); 

       return new Point(center.X + xdirection * x, center.Y + ydirection * y); 
      } 
     } 
     else 
     { 
      return null; 
     } 
    } 
} 
3

Kullanım MouseMove ve Canvas isabet test için bir Arka Plan sahip olduğundan emin olun.

XAML:

<Canvas MouseMove="Canvas_MouseMove" 
     Background="Transparent"> 
    <Ellipse x:Name="eye" 
      Width="50" 
      Height="20" 
      Fill="Blue" /> 
</Canvas> 

Codebehind:

private void Canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) 
{ 
    var pos = e.GetPosition((Canvas)sender); 
    Canvas.SetLeft(eye, pos.X); 
    Canvas.SetTop(eye, pos.Y); 
} 
+0

Teşekkür Chris arkasında kod: ... farenin mainCanvas'a girmesini diliyorum, tuval_eye girmeden gözün tuval_eye girmesine izin vermeyin. önce, umarım görevimin bir noktasını alırsın. – JayJay

+0

JayJay'in de XAML'de tanımlanan 8 saniyelik bir gecikme süresi istediği anlaşılıyor. – bitbonk

1

Eğer animasyon kullanıldıktan sonra bir animasyon özelliklerini değiştiremez hüküm dışında, neredeyse doğrudur yaptığı gibi. Clone()'u kullanarak yeni bir animasyon oluşturup düzeltin, eski animasyonu kaldırın ve ardından yeni değiştirilmiş olanı uygulayın.

İlgili konular