2010-11-04 2 views
5

Je fais une application Wpf et je crée un contrôle avec la forme d'un oeil, je mets une ellipse (oeil) dans un canevas et mon but est quand le curseur de la souris entre dans la toile l'Ellipse suit le curseur de la souris. Avez-vous une suggestion comment effectuer cette tâche? Merci beaucoup pour votre attention.Objet suivre le curseur de la souris

Vive

EDIT

je mettre à jour mon code en XAML:

<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> 

et dans le code derrière:

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(); 
    } 

maintenant mon but est quand je déplace la souris dans la zone Canvas (LayoutRoot) l'Ellipse (ctrCircle) se déplace uniquement à l'intérieur de la bordure (border_eye) et ne pas surmonter la zone de la "frontière_eye" cet effet est similaire à un œil.

Avez-vous des commentaires à formuler pour cette étape?

Merci beaucoup

Ayez un beau jour.

Vive

Répondre

7

Voici un exemple de réalisation d'un œil dans un canevas WPF à l'aide du Rx framework. L'utilisation de Rx au lieu de s'attacher directement à l'événement de déplacement de la souris vous permet de mettre en mémoire tampon les événements et de ne mettre à jour que la position de la pupille toutes les 10 millisecondes, ce qui réduit la charge globale du processeur.

Le 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> 

et le code derrière

/// <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

Utilisez MouseMove et assurez-vous que le canevas a un arrière-plan pour les tests de succès.

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

Merci Chris j'ai oublié d'écrire un détail, le séjour des yeux dans un autre composant j'écrire le code: ... donc je souhaite que quand la souris entre dans mainCanvas l'oeil bouge à l'intérieur du canvas_eye sans sortir de la bordure de canvas_eye.Sorry pour ma mauvaise explication avant, j'espère que vous aurez compris le but de ma tâche. – JayJay

+0

Il semble que JayJay souhaite également un délai d'accélération de 8 secondes, défini en XAML. – bitbonk

1

La façon dont vous l'avez fait est presque correct, sauf que vous ne pouvez pas modifier les propriétés d'une animation après l'animation a été utilisé. Vous devez créer une nouvelle animation en utilisant Clone() et le modifier, supprimer l'ancienne animation et ensuite appliquer la nouvelle.

Questions connexes