カーソルを追いかけるイメージ その 2
昨日のプログラムはどうも納得がいきません。ちょっと動きが悪い。マウスを動かさないでいる時に、イメージが少しずつマウスカーソルに重なっていく方がいいですね。
なので、今日はイベントではなく、周期的にマウスカーソルの位置を取得して、それをもとにイメージを描画する方法でやってみました。
マウスカーソルの位置を取得するのは JavaFX にはなさそうなので、Java の AWT の MouseInfo を使っています。ただ、MouseInfo でマウスカーソルの位置を取得するのは、サンドボックスではできません。だから、この方法を使ったアプリケーションを Java Web Start か Applet にした場合は署名が必要です。
周期的に位置を取得するのは Timeline でやってます。
var timeline = Timeline { repeatCount: Timeline.INDEFINITE keyFrames : [ KeyFrame { time : 50ms action: function() { var point:PointerInfo = MouseInfo.getPointerInfo(); var x: Number = point.getLocation().x; var y: Number = point.getLocation().y; x = x - frame.x - frame.window.getInsets().left; y = y - frame.y - frame.window.getInsets().top; insert x before previousX[0]; delete previousX[4]; insert y before previousY[0]; delete previousY[4]; } } ] }; timeline.start();
こうすると、50ミリ秒ごとに action 関数がコールされます。
MouseInfo で取得できる位置はスクリーンの絶対座標なので、アプリケーションのローカル座標に変換しています。
Frame クラスの window アトリビュートは JavaFX の javafx.application.Window オブジェクトではなくて、AWT の java.awt.Window オブジェクトです。だから、Window クラスの getInsets とか呼べるわけです。
スクリーンショットは昨日と区別がつかないのでのせませんが、昨日のバージョンよりだんぜん動きがいいです。
一応、すべてのソースをのせておきます。
import javafx.application.Frame; import javafx.application.Stage; import javafx.scene.Cursor; import javafx.scene.Node; import javafx.input.MouseEvent; import javafx.scene.geometry.Rectangle; import javafx.scene.image.ImageView; import javafx.scene.paint.Color; import java.awt.Dimension; import java.awt.MouseInfo; import java.awt.Point; import java.awt.PointerInfo; import java.awt.Toolkit; import java.awt.geom.Point2D; import java.lang.System; import java.net.URL; import javafx.scene.image.Image; import javafx.animation.Timeline; import javafx.animation.KeyFrame; var cursor: Cursor = Cursor { awtType: java.awt.Cursor.CUSTOM_CURSOR awtCursor: { var toolkit:Toolkit = Toolkit.getDefaultToolkit(); var image: java.awt.Image = toolkit.getImage(new URL("{__DIR__}duke0.gif")); toolkit.createCustomCursor(image, new Point(8, 0), "DUKE"); } }; var previousX: Number[] = [-10000, -10000, -10000, -10000]; var previousY: Number[] = [-10000, -10000, -10000, -10000]; var images: ImageView[] = [ ImageView { x: bind previousX[0] y: bind previousY[0] image: Image { url: "{__DIR__}duke1.gif" }, }, ImageView { x: bind previousX[1] y: bind previousY[1] image: Image { url: "{__DIR__}duke2.gif" }, }, ImageView { x: bind previousX[2] y: bind previousY[2] image: Image { url: "{__DIR__}duke3.gif" }, }, ImageView { x: bind previousX[3] y: bind previousY[3] image: Image { url: "{__DIR__}duke4.gif" }, }, ]; var frame = Frame { title: "CursorSample" width: 200 height: 200 closeAction: function() { java.lang.System.exit( 0 ); } visible: true stage: Stage { content: [ Rectangle { cursor: cursor x: 10, y: 10 width: 160, height: 140 fill: Color.AQUAMARINE onMouseExited: function(event: MouseEvent) { for (images in images) { images.visible = false; } } onMouseEntered: function(event: MouseEvent) { for (images in images) { images.visible = true; } } }, images ] } } var timeline = Timeline { repeatCount: Timeline.INDEFINITE keyFrames : [ KeyFrame { time : 50ms action: function() { var point:PointerInfo = MouseInfo.getPointerInfo(); var x: Number = point.getLocation().x; var y: Number = point.getLocation().y; x = x - frame.x - frame.window.getInsets().left; y = y - frame.y - frame.window.getInsets().top; insert x before previousX[0]; delete previousX[4]; insert y before previousY[0]; delete previousY[4]; } } ] }; timeline.start();