100
JavaFXグラフィックスと アニメーション入門 デスクトップにアナログ時計を表示しよう 高橋 徹(Java読書会BOF)

Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

  • Upload
    torutk

  • View
    1.084

  • Download
    8

Embed Size (px)

Citation preview

Page 1: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXグラフィックスとアニメーション入門

デスクトップにアナログ時計を表示しよう

高橋 徹(Java読書会BOF)

Page 2: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アジェンダ

目的

自己紹介

JavaFX駆け足紹介

アナログ時計の作り方

時計を描画するグラフィックス

3種類(画像、Java API、SVG)

針の動きをアニメーション

Page 3: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

本セッションの目的

JavaFXに興味あるが「敷居が高い」と感じている人

JavaFXを使っているがグラフィックスやアニメーションを使ってない人

JavaFXプログラムの超基本構造

簡単な例としてアナログ時計を作成

を対象に

を紹介します

Page 4: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

自己紹介

高橋 徹

Java読書会BOF代表http://www.javareading.com/bof/

日本JavaFXユーザーグループ参加https://groups.google.com/forum/#!forum/javafx-ja

ブログ等

ブログ http://d.hatena.ne.jp/torutk/

Twitter @boochnich

Page 5: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Java標準搭載GUIライブラリ

種類 搭載年 搭載版(Oracle JDK)

備考

AWT 1995年 JDK Alpha/Beta

Swing 1998年 JDK 1.2

JavaFX2011年 JDK 7u2 同梱形態

2014年 JDK 8

Page 6: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介 JavaFXの提供機能

ボタン、ラベル、グラフ等のUI部品

2Dグラフィックス(ベクトル、画像)

3Dグラフィックス(ポリゴン)

エフェクト(特殊効果)

アニメーション

サウンド

動画

Web表示

「Java SE Development Kit 8u40 Demos and Samples」に含まれるEnsemble を動かしてみると一通り確認できます。

Page 7: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

JavaFXの構成要素

1. Javaソースコード

JavaFX APIを呼ぶコードを記述

2. FXML(XML)

レイアウト・属性を記述

3. CSS

見栄えの記述

Page 8: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介 JavaFXプログラムの配布形態

1. Javaデスクトップアプリケーション javaコマンド

JARファイル

2. ブラウザーから起動(Web Start)リンクからダウンロードおよび実行

3. Webページ内で実行Webページを開くと実行(Applet)

4. ネイティブバンドル EXE、MSI、RPM、DMG

Page 9: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成

ステップ1

空のウィンドウを表示

ステップ2

ウィンドウ内に文字列を表示

Page 10: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ1)

package hello;

import javafx.application.Application;import javafx.stage.Stage;

public class HelloJavaFx extends Application {

@Overridepublic void start(Stage stage) {

stage.show();}

}

Page 11: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ1)

package hello;

import javafx.application.Application;import javafx.stage.Stage;

public class HelloJavaFx extends Application {

@Overridepublic void start(Stage stage) {

stage.show();}

}

使うクラスは・Application・Stageの2つ

Page 12: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ1)

package hello;

import javafx.application.Application;import javafx.stage.Stage;

public class HelloJavaFx extends Application {

@Overridepublic void start(Stage stage) {

stage.show();}

}

Applicationクラスは、JavaFXアプリケーションの制御を司る。

Application抽象クラスをサブクラス化し、抽象メソッドstartをオーバーライドする

Page 13: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ1)

package hello;

import javafx.application.Application;import javafx.stage.Stage;

public class HelloJavaFx extends Application {

@Overridepublic void start(Stage stage) {

stage.show();}

}

Stageクラスは、トップレベルウィンドウを表す。

startメソッドで受け取るStageインスタンスはデフォルト非表示であり、showメソッドを呼んで可視とする。

Page 14: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ1)

package hello;

import javafx.application.Application;import javafx.stage.Stage;

public class HelloJavaFx extends Application {

@Overridepublic void start(Stage stage) {

stage.show();}

}

mainメソッドがなくてもOK

Page 15: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello world(ステップ1)の実演

Page 16: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ2)

シーングラフの構築

Stage Scene

Node Node…

Node Node…

シーングラフと呼ぶツリー構造

Parent

Node

Page 17: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Scene Parent

Node

Hello worldを作成(ステップ2)

シーングラフの構築

今回構築するシーングラフ

Page 18: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Scene Group

Label

Hello worldを作成(ステップ2)

シーングラフの構築

今回構築するシーングラフ

Page 19: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Scene Group

Label

Hello worldを作成(ステップ2)

シーングラフの構築

Group root = new Group();Label hello = new Label(...);root.getChildren().add(hello);

Scene scene = new Scene(root);stage.setScene(scene);

Page 20: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Scene Group

Label

Hello worldを作成(ステップ2)

シーングラフの構築

Group root = new Group();Label hello = new Label(...);root.getChildren().add(hello);

Scene scene = new Scene(root);stage.setScene(scene);

Page 21: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Scene Group

Label

Hello worldを作成(ステップ2)

シーングラフの構築

Group root = new Group();Label hello = new Label(...);root.getChildren().add(hello);

Scene scene = new Scene(root);stage.setScene(scene);

Page 22: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Stage Group

Label

Hello worldを作成(ステップ2)

シーングラフの構築

Group root = new Group();Label hello = new Label(...);root.getChildren().add(hello);

Scene scene = new Scene(root);stage.setScene(scene);

Scene

Page 23: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ2)

ソースコード(1/2)package com.torutk.hellofx;

import javafx.application.Application;import javafx.stage.Stage;import javafx.scene.Group;import javafx.scene.Scene;import javafx.scene.control.Label;

Page 24: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello worldを作成(ステップ2)

ソースコード(2/2)

public class HelloJavaFx extends Application {@Overridepublic void start(Stage stage) {

Group root = new Group();Label helloLabel = new Label("Hello, JavaFX world");root.getChildren().add(helloLabel);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}}

Page 25: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFX駆け足紹介

Hello world(ステップ2)の実演

Page 26: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

きっかけ

Windows 7のガジェット機能でアナログ時計を表示

Windows 8でガジェットが廃止

ならば、自分で作ってみよう!

Page 27: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

アナログ時計の要素

時計を描画する

針を時間の経過に応じて動かす

Page 28: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方 アナログ時計の要素

時計を描画する

時計盤

短針 長針

秒針

中心

Page 29: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

アナログ時計の要素

針を時間の経過に応じて動かす

短針: 12時間で1回転

長針: 60分間で1回転

秒針: 1分間(60秒間)で1回転

Page 30: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方 時計の描画

画像を重ねて描画

JavaのAPI(2Dグラフィックス)で描画

SVGデータで描画

Page 31: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

時計盤: clockDial.png

短針 : clockHourHand.png

長針 : clockMinuteHand.png

秒針 : clockSecondsHand.png

中心 : clockCenterPoint.png

Page 32: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

シーングラフの構築

Stage Scene

Node Node…

Node Node…

シーングラフ

Parent

Node

Page 33: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

シーングラフの構築

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 34: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

ソースコード

public void start(Stage stage) {StackPane root = new StackPane();ImageView clockDial = new ImageView(new Image("file:clockDial.png"));ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}

Page 35: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

ソースコード

public void start(Stage stage) {

StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Page 36: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 37: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 38: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {

StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 39: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 40: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 41: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 42: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 43: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

public void start(Stage stage) {StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

ImageView(時計盤)

StackPane

ImageView(短針)

ImageView(長針)

ImageView(秒針)

ImageView(中心)

Page 44: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

ソースコード

public void start(Stage stage) {

StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}

Page 45: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

ソースコード

public void start(Stage stage) {

StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}

Scene StackPane

Page 46: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画

ソースコード

public void start(Stage stage) {

StackPane root = new StackPane();

ImageView clockDial = new ImageView(new Image("file:clockDial.png"));

ImageView hourHand = new ImageView(new Image("file:clockHourHand.png"));

ImageView minuteHand = new ImageView(new Image("file:clockMinuteHand.png"));

ImageView secondsHand = new ImageView(new Image("file:clockSecondsHand.png"));

ImageView centerPoint = new ImageView(new Image("file:clockCenterPoint.png"));

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondsHand, centerPoint

);

Scene scene = new Scene(root);

stage.setScene(scene);stage.show();

}

Stage Scene

Page 47: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画の実演

Page 48: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方 針を時間の経過に応じて動かす

短針: 12時間で1回転

長針: 60分間で1回転

秒針: 1分間(60秒間)で1回転

アニメーション

javafx.animation.RotateTransition

Nodeをお手軽にアニメーションする便利クラスTransitionのひとつで、回転を扱う

Transitionでは物足りないアニメーションを作成するには、Timelineを使う

Page 49: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

Page 50: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

・1回転に要する時間(duration)、・回転するNode・回転開始角度(startAngle)を指定し、RotateTransitionを生成するcreateRotateTransitionメソッド

Page 51: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

1回転に要する時間と回転するNodeを指定し、RotateTransitionをインスタンス化

Page 52: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

RotateTransitionインスタンスに回転開始角度を設定

Page 53: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

RotateTransitionインスタンスに回転角度を設定(開始角度からの増分)

Page 54: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

開始角度(fromAngle)

回転角度(byAngle)

Page 55: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

RotateTransitionインスタンスに繰り返し回数を設定(INDEFINITE は無限)

Page 56: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

針の回転を表すRotateTransitionを生成

private RotateTransition createRotateTransition(Duration duration, Node node, double startAngle

) {RotateTransition rt =

new RotateTransition(duration, node);rt.setFromAngle(startAngle);rt.setByAngle(360);rt.setCycleCount(Animation.INDEFINITE);rt.setInterpolator(Interpolator.LINEAR);return rt;

}

RotateTransitionインスタンスにアニメーション加減速を設定(LINEAR は等速)

Page 57: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

秒針:1分間(60秒間)で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition secondsHandTransition = createRotateTransition(

Duration.seconds(60),secondsHand,getAngleOfSeconds(LocalTime.now())

);secondsHandTransition.play();

private static double getAngleOfSeconds(LocalTime time) {return time.getSecond() * 360 / 60;

}

Page 58: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

秒針:1分間(60秒間)で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition secondsHandTransition = createRotateTransition(

Duration.seconds(60),secondsHand,getAngleOfSeconds(LocalTime.now())

);secondsHandTransition.play();

private static double getAngleOfSeconds(LocalTime time) {return time.getSecond() * 360 / 60;

}

1回転の期間をjavafx.util.Duration で指定

Page 59: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

秒針:1分間(60秒間)で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition secondsHandTransition = createRotateTransition(

Duration.seconds(60),secondsHand,getAngleOfSeconds(LocalTime.now())

);secondsHandTransition.play();

private static double getAngleOfSeconds(LocalTime time) {return time.getSecond() * 360 / 60;

}

回転するNodeを指定(秒針のImageView)

Page 60: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

秒針:1分間(60秒間)で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition secondsHandTransition = createRotateTransition(

Duration.seconds(60),secondsHand,getAngleOfSeconds(LocalTime.now())

);secondsHandTransition.play();

private static double getAngleOfSeconds(LocalTime time) {return time.getSecond() * 360 / 60;

}

現在時刻から秒針の回転開始角度を計算

Page 61: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

秒針:1分間(60秒間)で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition secondsHandTransition = createRotateTransition(

Duration.seconds(60),secondsHand,getAngleOfSeconds(LocalTime.now())

);secondsHandTransition.play();

private static double getAngleOfSeconds(LocalTime time) {return time.getSecond() * 360 / 60;

}

アニメーションの開始

Page 62: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

長針:60分間で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition minuteTransition = createRotateTransition(

Duration.minutes(60),minuteHand,getAngleOfMinute(LocalTime.now())

);minuteTransition.play();

private static double getAngleOfMinute(LocalTime time) {return (time.getMinute() + time.getSecond() / 60d) * 360 / 60;

}

1回転は60分間

現在時刻から短針の回転開始角度を計算

短針のImageView

Page 63: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

短針:12時間で1回転

createRotateTransitionメソッドを呼ぶ

RotateTransition hourTranslation = createRotateTransition(

Duration.hours(12),hourHand,getAngleOfHour(LocalTime.now())

);hourTranslation.play();

private static double getAngleOfHour(LocalTime time) {return (time.getHour() % 12 + time.getMinute() / 60d +

time.getSecond() / (60d * 60d)) * 360 / 12;

}

1回転は12時間

現在時刻から長針の回転開始角度を計算

長針のImageView

Page 64: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

画像を重ねて描画+針の回転の実演

Page 65: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方 アナログ時計の描画方法

画像を重ねて描画

JavaのAPI(2Dグラフィックス)で描画

SVGデータで描画

Page 66: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

時計盤: Circle, Line, RadialGradient, Rotate

短針 :

長針 :

秒針 : Line

中心 : Circle

Path, MoveTo, LineTo

Page 67: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

シーングラフの構築

Stage Scene

Node Node…

Node Node…

シーングラフ

Parent

Node

Page 68: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

シーングラフの構築

Stage Scene

Pane(時計盤)

StackPane

Pane(短針)

Pane(長針)

Pane(秒針)

Pane(中心)

Page 69: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

public void start(Stage stage) {StackPane root = new StackPane();Node clockDial = createClockDial();Node hourHand = createHourHand();Node minuteHand = createMinuteHand();Node secondHand = createSecondHand();Node centerPoint = createCenter();

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondHand, centerPoint

);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}

Page 70: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

シーングラフの構築

Stage Scene

Pane(時計盤)

StackPane

Pane(短針)

Pane(長針)

Pane(秒針)

Pane(中心)

Page 71: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

シーングラフの構築

Circle

Pane(時計盤)

Group

Line Line Line・・・

60個のライン

Page 72: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

時計盤(Circle)

Node createCircle() {RadialGradient gradient = new RadialGradient(

0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE,new Stop(0.8, Color.WHITE),new Stop(0.9, Color.BLACK),new Stop(0.95, Color.WHITE),new Stop(1.0, Color.BLACK)

);Circle circle = new Circle(

100, 100, 100, gradient);return circle;

}

(0,0)

(200,200)

(100,100)

Page 73: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

時計盤(Line)

Node createTickMark(int n) {Line line;if (n % 5 == 0) {

line = new Line(100, 100 * 0.12, 100, 100 * 0.2);} else {

line = new Line(100, 100 * 0.15, 100, 100 * 0.16);}line.getTransforms().add(new Rotate(360 / 60 * n, 100, 100));line.setStrokeWidth(2);return line;

}60個で1周する回転

Page 74: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

時計盤(Group)

Node createTickMarks() {Group tickMarkGroup = new Group();List<Node> tickMarks = IntStream.range(0, 60)

.mapToObj(this::createTickMark)

.collect(toList());tickMarkGroup.getChildren().addAll(tickMarks);return tickMarkGroup;

}

Page 75: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

短針/長針共通の描画Node createHourOrMinuteHand(

double stretchRelativeToRim, Color color) {

Path path = new Path(new MoveTo(100, 100),new LineTo(100 * 0.9, 100 * 0.9),new LineTo(100, stretchRelativeToRim),new LineTo(100 * 1.1, 100 * 0.9),new LineTo(100, 100)

);path.setFill(color);path.setStroke(Color.TRANSPARENT);return path;

}

① ②②

④①

塗りつぶし

Page 76: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画

秒針

Node createSecondHand() {Pane pane = new Pane();pane.setPrefSize(100 * 2, 100 * 2);Line line = new Line(100, 100 * 1.1, 100, 100 * 0.2);pane.getChildren().add(line);return pane;

}

Page 77: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

JavaのAPIで描画の実演

Page 78: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

画像を重ねて描画におけるアニメーションと実装は同一

Page 79: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方 アナログ時計の描画方法

画像を重ねて描画

JavaのAPI(2Dグラフィックス)で描画

SVGデータで描画

Page 80: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータについてScalable Vector Graphics

javafx.scene.shape.SVGPath

SVG 1.1仕様書(2版)の8章 Paths

日本語訳http://www.hcn.zaq.ne.jp/___/SVG11-2nd/paths.html

Page 81: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGパスデータについて

MoveTo, LineTo

“M 100 100 L 90 90”

円弧

“A 100 100 0 1 1 99 0”

MoveTo(100, 100); LineTo(90, 90)

Circle(100, 100, 100) に近似

Page 82: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGパスデータについて

円を定義するコマンドがない

“A 100 100 0 1 1 99 0”

Circle(100, 100, 100) に近似

Page 83: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

public void start(Stage stage) {StackPane root = new StackPane();Node clockDial = createClockDial();Node hourHand = createHourHand();Node minuteHand = createMinuteHand();Node secondHand = createSecondHand();Node centerPoint = createCenter();

root.getChildren().addAll(clockDial, hourHand, minuteHand, secondHand, centerPoint

);

Scene scene = new Scene(root);stage.setScene(scene);stage.show();

}

Page 84: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

時計盤(枠)

Node createCircle() {RadialGradient gradient = new RadialGradient(

0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE,new Stop(0.8, Color.WHITE),new Stop(0.9, Color.BLACK),new Stop(0.95, Color.WHITE),new Stop(1.0, Color.BLACK)

);SVGPath svg = new SVGPath();svg.setContent(

“M 100 0 A 100 100 0 1 1 99 0”);svg.setFill(gradient);return circle;

}

(0,0)

(200,200)

(100,100)

JavaのAPIで描画から変更した部分

Page 85: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

時計盤(分刻み)

Node createTickMarks() {SVGPath svg = new SVG();svg.setContent(

“M 100,12 L 100,20 M 108.9,15.5 ...”);svg.setStroke(Color.BLACK);svg.setStrokeWidth(2);return svg;

} 刻み1つ毎に M nn,nn L nn,nn を記述

Page 86: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

短針の描画

Node createHourHand() {SVGPath svg = new SVGPath();svg.setContent(“M 100,100 L 90,90, L 100,40 L 110,90 Z”);Pane pane = new Pane(svg);pane.setPrefSize(100*2, 100*2);return pane;

}

Page 87: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

長針の描画

Node createMinuteHand() {SVGPath svg = new SVGPath();svg.setContent(“M 100,100 L 90,90, L 100,20 L 110,90 Z”);Pane pane = new Pane(svg);pane.setPrefSize(100*2, 100*2);return pane;

}

Page 88: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画

秒針の描画

Node createSecondHand() {SVGPath svg = new SVGPath();svg.setContent(“M 100,110 L 100,20”);svg.setStroke(Color.GLAY);Pane pane = new Pane(svg);pane.setPrefSize(100 * 2, 100 * 2);return pane;

}

Page 89: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

SVGデータで描画の実演

Page 90: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

針を動かすアニメーション

画像を重ねて描画におけるアニメーションと実装は同一

Page 91: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

アナログ時計の作り方

ウィンドウ枠の非表示

public void start(Stage stage) {:Scene scene = new Scene(root, Color.TRANSPARENT);stage.initStyle(StageStyle.TRANSPARENT);:

}

Page 92: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

最後に(1/2) JavaFXの最小限のプログラムとして

Hello worldを紹介

アナログ時計を題材に時計のグラフィックス表示

3種類(画像を重ねる、Java API、SVG)

時計の針の回転をアニメーション

デモのコードは次からダウンロードhttps://github.com/torutk/jjugccc2015spring-javafx

Page 93: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

最後に(2/2)

本セッションの元ネタhttp://www.torutk.com/projects/swe/wiki/JavaFX

から、「JavaFXとアナログ時計」のリンクへ

Timelineを使った回転のアニメーション

SceneBuilderでSVGPathやRadialGradientの取り扱い

マウスドラッグによる時計の移動

マウスホイール、ピンチ操作での時計の拡大縮小

ポップアップメニュー

Page 94: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

Q&A

Page 95: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXアニメーション(補足) JavaFX関連のスレッド

JavaFX Applicationスレッド 入力、pulse、ユーザータスクに応じて

シーングラフを更新 renderコマンド作成

QuantumRenderスレッド renderコマンドを実行し描画

JavaFX pulse アニメーション中は、16msタイマーで発生(最大

60FPS)

(参考)JavaOne SF 2014 CON2262 “Be in Control of Your JavaFX Mission”

Page 96: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXアニメーション(補足) JavaFX pulse

JavaFX

Render

Timer

アニメーション処理、シーングラフ更新、renderコマンド作成

render実行、描画

16msタイマー

Page 97: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXアニメーション(補足)

JavaFX pulseをFlight Recorderで調査

Page 98: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXにmain不要

javafx.application.Applicationを継承したクラスを指定してjavaコマンドで起動するとき、mainメソッドがなくてもよい

「JavaFXアプリケーションクラスにmainメソッドがなくてもよい訳」

http://d.hatena.ne.jp/torutk/20150402/p1

Page 99: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

ラスター v.s. ベクター

拡大縮小への対応

拡大時の表示具合

画像(ラスター)で実現 SVG(ベクター)で実現

Page 100: Java FXグラフィックスとアニメーション入門(JJUG CCC 2015 Spring G-7)

JavaFXの主な特徴 Java API FXMLとGUIデザインツール(Scene Builder) WebView(WebKitベース) Swing相互互換性 組込みUI部品とCSS テーマ(Modena) 3Dグラフィックス Canvas API 印刷API リッチテキスト マルチタッチ Hi-DPI ハードウェアアクセラレートグラフィックス メディアエンジン JRE内蔵アプリケーション配布