カーソルを追いかけるイメージ

f:id:skrb:20081115003448p:image:right

前回カスタムカーソルを作ったことの続き。

せっかくカーソルを変えたので、よくあるカーソルを追いかけるイメージというのを JavaFX でも作ってみようと思います。

ここではマウスが移動するイベントを拾って、その都度シーケンスに挿入して、古いものは捨てるということをやっています。

ようするにシーケンスの先頭は現在のマウスの位置、次が 1 つ前のイベントの時のマウスの位置、次が 2 つ前のイベント時のマウスの位置、というようになっています。

で、そのシーケンスをイメージの位置と同期 (つまり bind です) させてしまうというものです。

後は領域から出た時にイメージを非表示にして、領域に再び入ったら表示して、かつ位置も初期化するということをやってます。

完成品が右のイメージ。一番大きい Duke がマウスカーソルです。

import javafx.application.Frame;
import javafx.application.Stage;
import javafx.scene.Cursor;
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.Point;
import java.awt.Toolkit;
import java.lang.System;
import java.net.URL;
import javafx.scene.image.Image;

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), "MAGNIFIER");
    }
};

// とりあえず、見えそうもない場所に設定
var previousX: Number[] = [-10000, -10000, -10000, -10000, -10000];
var previousY: Number[] = [-10000, -10000, -10000, -10000, -10000];

// それぞれのイメージの位置は (previousX[i], previousY[i]) に bind
// previousX[0], previousY[0] は現在の位置なので使用しない
var images: ImageView[] = [
    ImageView {
        x: bind previousX[4]
        y: bind previousY[4]
        image: Image {
            url: "{__DIR__}duke4.gif"
        },
    },
    ImageView {    
        x: bind previousX[3]
        y: bind previousY[3]
        image: Image {
            url: "{__DIR__}duke3.gif"
        },
    },
    ImageView {    
        x: bind previousX[2]
        y: bind previousY[2]
        image: Image {
            url: "{__DIR__}duke2.gif"
        },
    },
    ImageView {    
        x: bind previousX[1]
        y: bind previousY[1]
        image: Image {
            url: "{__DIR__}duke1.gif"
        },
    },
];

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
                
                onMouseMoved: function(event: MouseEvent) {
                    // x 座標をシーケンスの先頭に追加
                    // 最後を削除する
                    var x = event.getX();
                    insert x before previousX[0];
                    delete previousX[5];
          
                    // y 座標も同じ
                    var y = event.getY();
                    insert y before previousY[0];
                    delete previousY[5];
                }
                
                onMouseExited: function(event: MouseEvent) {
                    // マウスカーソルが領域から出たら、イメージを非表示にする
                    for (images in images) {
                        images.visible = false;
                    } 
                }

                onMouseEntered: function(event: MouseEvent) {
                    // マウスカーソルが領域に入ったら、イメージを表示する
                    for (images in images) {
                        images.visible = true;
                    } 
                    // 領域に入った場所でシーケンスを初期化
                    var x = event.getX();
                    previousX = [x, x, x, x];
                    var y = event.getY();
                    previousY = [y, y, y, y];
                }
            },
            images
        ]
    }
}