Skip to content

Instantly share code, notes, and snippets.

@aoetk
Created November 25, 2012 11:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aoetk/4143183 to your computer and use it in GitHub Desktop.
Save aoetk/4143183 to your computer and use it in GitHub Desktop.
第8回JavaFX勉強会のサンプルアプリケーション
package aoetk.multitouch.sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* 第8回JavaFX勉強会に使用したマルチタッチサンプルアプリケーション。
*/
public class JavafxMultitouchSample extends Application {
/**
* アプリケーション開始処理。
* @param stage アプリケーションのステージ
* @throws Exception アプリケーション実行中に何らかの例外が発生
*/
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().
getResource("TouchRegion.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("JavaFXマルチタッチサンプル");
stage.show();
}
/**
* メインメソッド。
* @param args コマンドライン引数
*/
public static void main(String[] args) {
launch(args);
}
}
.border {
-fx-border-color: black;
-fx-border-width: 3;
}
.pagination .page {
-fx-background-color: #DDF1F8;
}
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<AnchorPane id="AnchorPane" prefHeight="680.0" prefWidth="1000.0" xmlns:fx="http://javafx.com/fxml" fx:controller="aoetk.multitouch.sample.TouchRegionController">
<children>
<TabPane fx:id="tabPane" prefHeight="680.0" prefWidth="1000.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<tabs>
<Tab text="タッチテスト">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Pane fx:id="touchPane" onTouchPressed="#handleTouchStart" prefHeight="606.0" prefWidth="960.0" styleClass="border" AnchorPane.bottomAnchor="56.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="14.0" />
<Label text="Touch Event Set ID:" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="20.0" />
<Label fx:id="lblEventSetId" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="151.0" />
<Label text="Touch Count:" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="197.0" />
<Label fx:id="lblTouchCount" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="291.0" />
<Label text="Touch x:" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="341.0" />
<Label fx:id="lblTouchX" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="407.0" />
<Label text="y:" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="469.0" />
<Label fx:id="lblTouchY" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="487.0" />
<Button layoutX="891.0" layoutY="600.0" mnemonicParsing="false" onAction="#handleBtnClearAction" prefHeight="30.0" prefWidth="86.0" text="クリア" />
</children>
</AnchorPane>
</content>
</Tab>
<Tab text="ズーム・ローテーションテスト">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Rectangle fx:id="rectangle" arcHeight="5.0" arcWidth="5.0" fill="#ff007a" height="200.0" onRotate="#handleRectangleRotation" onScroll="#handleRectangleScroll" onZoom="#handleRectangleZoom" stroke="BLACK" strokeType="INSIDE" width="200.0" AnchorPane.bottomAnchor="222.0" AnchorPane.rightAnchor="400.0" />
<GridPane id="GridPane" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0">
<children>
<Label text="縮尺:" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="0">
<font>
<Font size="50.0" fx:id="x1" />
</font>
</Label>
<Label fx:id="lblFactor" alignment="CENTER_RIGHT" font="$x1" text="100" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="0" />
<Label font="$x1" text="\%" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="0" />
<Label font="$x1" text="角度:" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="1" />
<Label fx:id="lblAngle" alignment="CENTER_RIGHT" font="$x1" text="0" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="1" />
<Label font="$x1" text="度" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
<Label font="$x1" text="Δx:" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="2" />
<Label font="$x1" text="Δy:" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="3" />
<Label id="lblAngle" fx:id="lblDeltaX" alignment="CENTER_RIGHT" font="$x1" text="0" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="2" />
<Label id="lblAngle" fx:id="lblDeltaY" alignment="CENTER_RIGHT" font="$x1" text="0" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="3" />
<Label font="$x1" text="px" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<Label font="$x1" text="px" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="10.0" prefWidth="130.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="160.0" minWidth="10.0" prefWidth="160.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="63.0" minWidth="10.0" prefWidth="63.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</children>
</AnchorPane>
</content>
</Tab>
<Tab text="コントロールのタッチ対応テスト">
<content>
<BorderPane prefHeight="200.0" prefWidth="200.0">
<center>
<Pagination fx:id="pagination" styleClass="bullet">
<BorderPane.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</BorderPane.margin>
</Pagination>
</center>
<right>
<ListView fx:id="lvFonts" prefHeight="200.0" prefWidth="230.0" />
</right>
</BorderPane>
</content>
</Tab>
</tabs>
</TabPane>
</children>
<stylesheets>
<URL value="@style.css" />
</stylesheets>
</AnchorPane>
package aoetk.multitouch.sample;
import static javafx.scene.paint.Color.*;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.Pagination;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.RotateEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.input.TouchEvent;
import javafx.scene.input.TouchPoint;
import javafx.scene.input.ZoomEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.util.Callback;
/**
* 第8回JavaFX勉強会に使用したマルチタッチサンプルアプリケーションのコントローラー。
*/
public class TouchRegionController implements Initializable {
/**
* タッチ場所に表示したサークルのタッチ移動に対するハンドラ。
*/
class TouchMoveHandler implements EventHandler<TouchEvent> {
private double startSceneX;
private double startSceneY;
public TouchMoveHandler(double startSceneX, double startSceneY) {
this.startSceneX = startSceneX;
this.startSceneY = startSceneY;
}
@Override
public void handle(TouchEvent event) {
final Circle circle = (Circle) event.getTarget();
final TouchPoint point = event.getTouchPoint();
relocateCircle(circle, point.getSceneX() - startSceneX + circle.getLayoutX(),
point.getSceneY() - startSceneY + circle.getLayoutY());
startSceneX = point.getSceneX();
startSceneY = point.getSceneY();
}
}
/** タッチした場所に表示する円の色定義。10色サイクル。 */
private static final Color[] COLORS = new Color[] { BLUE, RED, GREEN, VIOLET, BROWN, CYAN, YELLOW, BLACK, GREY, PINK };
/** 円の半径。 */
private static final double CIRCLE_RADIUS = 30.0;
/** フォント一覧を表示するページネーションコントロールの1ページあたりの表示数。 */
private static final int FONTS_PER_PAGE = 25;
/** 円が表示された総数。 */
private int circleCount = 0;
/** システムがサポートするフォントのリスト。 */
private List<String> fonts;
/** タッチテストの領域。 */
@FXML
private Pane touchPane;
/** 総タッチ数を表示するラベル。 */
@FXML
private Label lblTouchCount;
/** タッチイベントのIDを表示するラベル。 */
@FXML
private Label lblEventSetId;
/** タッチポイントのx座標を表示するラベル。 */
@FXML
private Label lblTouchX;
/** タッチポイントのy座標を表示するラベル。 */
@FXML
private Label lblTouchY;
/** フォント一覧を表示するページネーションコントロール。 */
@FXML
private Pagination pagination;
/** ジェスチャーイベントの対象となる四角形。 */
@FXML
private Rectangle rectangle;
/** ズームイベントの倍率を表示するラベル。 */
@FXML
private Label lblFactor;
/** ローテーションイベントの角度を表示するラベル。 */
@FXML
private Label lblAngle;
/** スクロールイベントのx方向の移動量を表示するラベル。 */
@FXML
private Label lblDeltaX;
/** スクロールイベントのy方向の移動量を表示するラベル。 */
@FXML
private Label lblDeltaY;
/** フォント一覧を表示するリスト。 */
@FXML
private ListView<String> lvFonts;
/**
* タッチテストの領域で発生したタッチ開始イベントのハンドラ。
* タッチ位置にサークルを描画する。
* サークルにはタッチ位置に応じて移動するためのイベントハンドラと、
* ダブルタップ時に消去するためのイベントハンドラを登録する。
* @param event タッチイベント情報
*/
@FXML
private void handleTouchStart(TouchEvent event) {
if (!(event.getTarget() instanceof Circle)) {
circleCount++;
final TouchPoint point = event.getTouchPoint();
lblTouchCount.setText(Integer.toString(event.getTouchCount()));
lblEventSetId.setText(Integer.toString(event.getEventSetId()));
final Circle circle = new Circle(CIRCLE_RADIUS, COLORS[circleCount % 10]);
relocateCircle(circle, point.getX(), point.getY());
circle.setOnTouchMoved(new TouchMoveHandler(point.getSceneX(), point.getSceneY()));
circle.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount() >= 2) {
touchPane.getChildren().remove((Node) event.getTarget());
}
}
});
lblTouchX.setText(Double.toString(point.getX()));
lblTouchY.setText(Double.toString(point.getY()));
touchPane.getChildren().add(circle);
}
}
/**
* クリアボタンクリック時の処理。サークルを全て消去する。
* @param event アクションイベント情報
*/
@FXML
private void handleBtnClearAction(ActionEvent event) {
touchPane.getChildren().clear();
}
/**
* 四角形に対するズームイベントの処理。ズーム倍率に合わせて四角形のスケールを変更する。
* @param event ズームイベント情報
*/
@FXML
private void handleRectangleZoom(ZoomEvent event) {
double totalScale = event.getZoomFactor() * rectangle.getScaleX();
rectangle.setScaleX(totalScale);
rectangle.setScaleY(totalScale);
lblFactor.setText(Integer.toString((int) (totalScale * 100)));
event.consume();
}
/**
* 四角形に対するローテーションイベントの処理。回転に合わせて四角形を回転する。
* @param event ローテーションイベント情報
*/
@FXML
private void handleRectangleRotation(RotateEvent event) {
double totalAngle = event.getAngle() + rectangle.getRotate();
rectangle.setRotate(totalAngle);
lblAngle.setText(Integer.toString((int) totalAngle));
event.consume();
}
/**
* 四角形に対するスクロールイベントの処理。スクロール方向に合わせて移動する。
* @param event スクロールイベント情報
*/
@FXML
private void handleRectangleScroll(ScrollEvent event) {
if (!event.isInertia()) {
double totalDeltaX = rectangle.getTranslateX() + event.getDeltaX();
double totalDeltaY = rectangle.getTranslateY() + event.getDeltaY();
rectangle.setTranslateX(totalDeltaX);
rectangle.setTranslateY(totalDeltaY);
lblDeltaX.setText(Integer.toString((int) totalDeltaX));
lblDeltaY.setText(Integer.toString((int) totalDeltaY));
}
event.consume();
}
/**
* コントローラーの初期処理。
* システムがサポートするフォントを取得し、ページネーションコントロールとリストに設定する。
* @param url FXMLのロケーション
* @param rb リソースバンドル
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
fonts = Font.getFamilies();
pagination.setPageCount(fonts.size() / FONTS_PER_PAGE);
pagination.setPageFactory(new Callback<Integer, Node>() {
@Override
public Node call(Integer idx) {
return createPage(idx);
}
});
lvFonts.setItems(FXCollections.observableArrayList(fonts));
}
/**
* サークルの位置を変更する。
* @param circle 対象となるサークル
* @param sceneX サークルのシーングラフ上におけるx座標
* @param sceneY サークルのシーングラフ上におけるy座標
*/
private void relocateCircle(final Circle circle, double sceneX, double sceneY) {
circle.relocate(sceneX - CIRCLE_RADIUS, sceneY - CIRCLE_RADIUS);
}
/**
* ページネーションコントロールに表示するページを生成する。
* @param idx ページインデックス
* @return ページネーションコントロールに表示するページ
*/
private VBox createPage(int idx) {
VBox box = new VBox(5.0);
int page = idx * FONTS_PER_PAGE;
for (int i = page; i < page + FONTS_PER_PAGE; i++) {
Label lblFont = new Label(fonts.get(i));
box.getChildren().add(lblFont);
}
return box;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment