Java etc...

アクセスカウンタ

help RSS JavaFX の Bind で三角形の面積を求める... の続き(2)

<<   作成日時 : 2012/12/28 02:07   >>

ブログ気持玉 0 / トラックバック 0 / コメント 0

If you prefer to read this article in ENGLISH, go to [in English] page.

JavaFX の Bind で三角形の面積を求める... の続き(1)の続き ...

入力だけでなく、出力も GUI を使ってみよう。

具体的には、
- X-Y軸の座標平面の第一象限にマップする(座標原点を左上から左下にする)
- 単位を cm にする(メモリの補助線を入れる)
- 3頂点の座標と面積の値を画面上部に表示する(表示桁も最小限に)
ということを考えた。

原点O は、左下から座標平面までのマージン 5 pixie とり、さらに x軸, y軸とも 5pixie の offset を取った位置とする。また、96ピクセル/インチを前提にしてピクセル単位から cm 単位に変換する。x軸, y軸のメモリ用補助線も表示するとしよう(細い線で)。さらに、画面上に表示する座標位置の書式は "%2.1f" という書式で表示する。小数点以下の表示桁を多くしても、表示する領域の限られていることだし。

これらを実装すると、次のようソースコードになった。

import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.binding.When;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.GroupBuilder;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.Label;
import javafx.scene.control.LabelBuilder;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFieldBuilder;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CircleBuilder;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineBuilder;
import javafx.scene.shape.RectangleBuilder;
import javafx.stage.Stage;

public class TriangleArea1 extends Application {
  private int clickcount = 0;
  private Circle c[] = new Circle[3];
  private Line l[] = new Line[3];
  private Line a_x_l[] = new Line[12];
  private Line a_y_l[] = new Line[12];
  private TextField tx[] = new TextField[3];
  private TextField ty[] = new TextField[3];
  private Label area_Label = new Label();

  private DoubleProperty org_x[] = new SimpleDoubleProperty[3];
  private DoubleProperty org_y[] = new SimpleDoubleProperty[3];
  private NumberBinding map_x[] = new NumberBinding[3];
  private NumberBinding map_y[] = new NumberBinding[3];
  private NumberBinding area;

  {
    for(int i = 0; i < 3; i++ ) {
      // 頂点を表現する点(Circle)と
      // 辺を表現する線(Line)を用意
      c[i] = CircleBuilder.create()
                          .radius(3.0)
                          .fill(Color.RED)
                          .build();
      l[i] = LineBuilder.create()
                          .strokeWidth(2.0)
                          .stroke(Color.RED)
                          .build();

      // 頂点の座標位置を表示する TextField を用意
      tx[i] = TextFieldBuilder.create()
                              .prefColumnCount(2)
                              .build();
      ty[i] = TextFieldBuilder.create()
                              .prefColumnCount(2)
                              .build();

      // クリックした位置をプロパティとして保持
      // (初期値は原点Oの位置のpixel値)
      org_x[i] = new SimpleDoubleProperty(10);
      org_y[i] = new SimpleDoubleProperty(490);

      // 画面に表示した座標系での座標位置
      // (クリックした位置のプロパティがバインドされ計算)
      map_x[i] = org_x[i].subtract(10)
                         .multiply(2.54)
                         .divide(96.0);
      map_y[i] = org_y[i].negate()
                         .add(490)
                         .multiply(2.54)
                         .divide(96.0);
    }

    // x軸、y軸の補助線を用意
    for (int i = 0; i < 12; i++) {
      double delta_y = 490.0 - (i+1) * (96.0 / 2.54);
      double delta_x = 10.0 + (i+1) * (96.0 / 2.54);
      a_x_l[i] = new Line(5, delta_y, 495, delta_y);
      a_x_l[i].setStrokeWidth((i+1)%5==0 ? 0.3 : 0.1);
      a_y_l[i] = new Line(delta_x, 5, delta_x, 495);
      a_y_l[i].setStrokeWidth((i+1)%5==0 ? 0.3 : 0.1);
    }
  }

  public TriangleArea1() {
    initialize();

    for(int i = 0; i < 3; i++) {
      int j = (i == 2) ? 0 : i+1;

      // 辺の始点終点に頂点の中心をバインド
      l[i].startXProperty().bind(c[i].centerXProperty());
      l[i].startYProperty().bind(c[i].centerYProperty());
      l[i].endXProperty().bind(c[j].centerXProperty());
      l[i].endYProperty().bind(c[j].centerYProperty());

      // 頂点を表現する点の中心にクリックした位置をバインド
      c[i].centerXProperty().bind(org_x[i]);
      c[i].centerYProperty().bind(org_y[i]);

      // 座標位置表示用 TextField の Text に
      // 座標位置の値の文字列表現をバインド
      tx[i].textProperty().bind(map_x[i].asString("%2.1f"));
      ty[i].textProperty().bind(map_y[i].asString("%2.1f"));
    }

    // 面積を3つの頂点の座標位置がバインドされ計算
    NumberBinding tmp_area =
             map_x[0].multiply(map_y[1])
        .add(map_x[1].multiply(map_y[2]))
        .add(map_x[2].multiply(map_y[0]))
        .subtract(map_x[0].multiply(map_y[2]))
        .subtract(map_x[1].multiply(map_y[0]))
        .subtract(map_x[2].multiply(map_y[1]))
        .divide(2.0);

    // 絶対値をとる計算を When().then().otherwise() で実装
    area = new When(tmp_area.lessThan(0))
              .then(tmp_area.negate())
              .otherwise(tmp_area);

    // 面積の値を表示するラベルの text を、
    // 計算された面積の値の文字列表現を使うようにバインド
    area_Label.textProperty().bind(
      new SimpleStringProperty("Area = ")
              .concat(area.asString("%2.1f")));
  }

  private void initialize() {
    clickcount = 0;
  }

  @Override public void start(Stage stage) {
    final Group root;
    Scene scene = SceneBuilder.create()
      .width(500).height(500)
      .fill(Color.WHITE)
      .root(root = GroupBuilder.create()
        .children(RectangleBuilder.create()
          .layoutX(5).layoutY(5)
          .width(490).height(490)
          .fill(Color.LIGHTSKYBLUE)
          .onMouseClicked(new EventHandler<MouseEvent>() {
            // クリック時のイベントハンドラ
            @Override public void handle(MouseEvent e) {
              if (clickcount > 2) { initialize(); }
              for (int j = clickcount; j < 3; j++) {
                org_x[j].set(e.getSceneX());
                org_y[j].set(e.getSceneY());
              }
              clickcount++;
            }
          }).build(),
        // 原点O を通る x 軸
        LineBuilder.create()
          .startX(5).startY(490)
          .endX(495).endY(490)
          .build(),
        // 原点O を通る y 軸
        LineBuilder.create()
          .startX(10).startY(5)
          .endX(10).endY(495)
          .build(),
        // x 軸の補助線(1cm刻み)
        a_x_l[0], a_x_l[1], a_x_l[2], a_x_l[3],
        a_x_l[4], a_x_l[5], a_x_l[6], a_x_l[7],
        a_x_l[8], a_x_l[9], a_x_l[10], a_x_l[11],
        // y 軸の補助線(1cm刻み)
        a_y_l[0], a_y_l[1], a_y_l[2], a_y_l[3],
        a_y_l[4], a_y_l[5], a_y_l[6], a_y_l[7],
        a_y_l[8], a_y_l[9], a_y_l[10], a_y_l[11],
        // 三角形の辺
        l[0], l[1], l[2],
        // 三角形の頂点
        c[0], c[1], c[2],
        // 座標位置及び面積の表示
        HBoxBuilder.create()
          .layoutX(10)
          .padding(new Insets(10, 10, 10, 10)).spacing(3)
          .alignment(Pos.BOTTOM_CENTER)
          .children(
            LabelBuilder.create().text("A(").build(),
            tx[0],
            LabelBuilder.create().text(",").build(),
            ty[0],
            LabelBuilder.create().text("),").build(),
            LabelBuilder.create().text("B(").build(),
            tx[1],
             LabelBuilder.create().text(",").build(),
            ty[1],
            LabelBuilder.create().text("),").build(),
            LabelBuilder.create().text("C(").build(),
            tx[2],
            LabelBuilder.create().text(",").build(),
            ty[2],
            LabelBuilder.create().text(") ⇒ ").build(),
            area_Label
          ).build()
      ).build()
    ).build();

    stage.setTitle("Triangle Area");
    stage.setScene(scene);
    stage.show();
  }

  public static void main(String[] args) {
    launch(args);
  }
}


頂点座標と面積を画面上に表示


いやいや長い ...
Builderクラスで Node を build しているのもあるけど、画面表示を凝るとこうなってしまうのかもしれない。FXML を使えばいいじゃんという声が聞こえてきそう。

これで、結果の表示も GUI 上に表現できるようにはなった。

せっかく、座標位置を TextField を使っているのだから、マウスクリックで座標を入力するだけでなく、TextField に直接、値を入力できるようにさせてみよう。

つづく ...

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
本 文
JavaFX の Bind で三角形の面積を求める... の続き(2) Java etc.../BIGLOBEウェブリブログ