昨日のプログラムはどうも納得がいきません。ちょっと動きが悪い。マウスを動かさないでいる時に、イメージが少しずつマウスカーソルに重なっていく方がいいですね。
なので、今日はイベントではなく、周期的にマウスカーソルの位置を取得して、それをもとにイメージを描画する方法でやってみました。
マウスカーソルの位置を取得するのは 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();