JavaFX FileChooser 〜ファイルの選択をする部品〜

FileChooserクラス

ブラウザ(Google Chrome, Safari, Edge etc..)で、ファイルを選択してアップロードするときのような、画面操作を実現するクラスFileChooserクラスを紹介します。

JavaFXはApplicationクラスを継承してlaunchを実行すれば起動できるシンプルな扱いで動かせます。

具体的には下のように書きます。参照先はこちらOracleDocsです。

コードの書き方

1. Applicationクラスを継承

作成したクラスにApplicationクラスを継承します。下のクラスは「HelloWorld」を作成して「extends Application」と追加しました。

import文は「import javafx.application.Application;」と書きます。

public class HelloWorld extends Application {

2. メインメソッドの実装

単純に下のように書けば動きます。メインメソッドで呼び出しているのはApplication#launch()メソッドです。継承しているので、そのまま呼び出せます。
※launchメソッドはstaticメソッドなので、メインメソッド内でも直接呼び出すことができます。

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

3. start()メソッドの実装

このメソッドをオーバーライドして描画する画面のプログラムを行います。
Application#start()メソッドをHelloWorldクラスでstart()メソッドを定義(実装)することで、オーバーライドすることができます。日本語にすると「上書き」です。
そんなわけで、HelloWorldクラスのlaunch()メソッドを起動することで、このクラスのstart()メソッドが動きます。

ファイルチューザーの扱い方

いよいよ、描画処理の内容に入ります。
下のように、インスタンス化して動かします。細かいところは、実装してみて確認してください(笑)

 // ファイルクラスをインスタンス化
 FileChooser fileChooser = new FileChooser();
 // ダイヤログを表示した時の文字(下のキャプチャ参照)
 fileChooser.setTitle("ファイルを選択してください。");
 // Mac(自分の端末)でやった場合はファイルタイプを指定するものがないので無効?
 fileChooser.getExtensionFilters().addAll(
         new ExtensionFilter("Text Files", "*.txt"),
         new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.gif"),
         new ExtensionFilter("Audio Files", "*.wav", "*.mp3", "*.aac"),
         new ExtensionFilter("All Files", "*.*"));
 File selectedFile = fileChooser.showOpenDialog(mainStage)

そして最後の行にあるファイルを書き出ししないとファイルが作成されません。

そして、キャンセルををした場合はFileがNullになるようです。

[rakuten ids="auc-dejima:10002899"]

関連ページ一覧

  1. Java Doc 読解 System
  2. Java Doc 読解〜System.out
  3. Java Doc読解 System.In
  4. JavaDoc 読解  Filesクラス 
  5. Java Doc読解 BufferedReader
  6. Java Doc 読解〜BufferedWriter

JavaFXでハローワールド〜OpenCVまで

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine〜




StepupPrograming 〜ループ文を学ぶ〜

イントロダクション

前回は、IF文を理解したと思います。不思議な設定は少し置いておきます。

このブログを読み進めていれば、以下のスキル(武器)を保有していると思います。

  1. JavaFXのラベルコントロール
  2. IF文の書き方を理解している
  3. Stringクラス(文字列)の記載、コントロール
  4. メソッドを作る(文字列を返却する)
  5. System.out.printlnメソッド

MAPを作る

そろそろ、それっぽいものを作りたいと思います。そのために新たな武器を取得してもらいます。

ループ(FOR)文を覚える

まずは、MAPとFOR文の関係がわからないと「やる気」が出ないと思います。参考に作成したものをみてください。詳しくはこちら

下のソースは、次のような処理を行っています。

  1. パネルのサイズをint型の配列で保持します。
  2. 使用する画像ファイル名を変数に保持(ここではgrass_light.pngのみ使用)
  3. GridPaneクラスで升目上にラベルを配置する準備
  4. GridPane#add()でラベルを追加
    ※createImageLbl()メソッドはファイル名を引数にしてImageLabelを返却します。具体的には、緑色のタイル(画像ファイル)を返却します。
grid.add(createImageLbl(lightGrass), 0, 1);

と書いているのは、「0行目の1カラム目にイメージ画像をセット」という意味になります。

<ソース>

// パネルサイズ
int[] size = {3, 5};
String lightGrass = "grass_light.png";
String deepGrass = "grass_deep.png";
String soilBasic = "soil_basic.png";
GridPane grid = new GridPane();
grid.add(createImageLbl(lightGrass), 0, 1);
grid.add(createImageLbl(lightGrass), 0, 2);
grid.add(createImageLbl(lightGrass), 0, 3);
grid.add(createImageLbl(lightGrass), 0, 4);
grid.add(createImageLbl(deepGrass), 1, 1);
grid.add(createImageLbl(deepGrass), 1, 2);
grid.add(createImageLbl(deepGrass), 1, 3);
grid.add(createImageLbl(deepGrass), 1, 4);
grid.add(createImageLbl(soilBasic), 2, 1);
grid.add(createImageLbl(lightGrass), 2, 2);
grid.add(createImageLbl(lightGrass), 2, 3);
grid.add(createImageLbl(lightGrass), 2, 4);
grid.add(createImageLbl(lightGrass), 3, 1);
grid.add(createImageLbl(soilBasic), 3, 2);
grid.add(createImageLbl(lightGrass), 3, 3);
grid.add(createImageLbl(lightGrass), 3, 4);
vBox.getChildren().add(grid);

なにやら同じようなコードが並んでいて使用するのがとても大変です。
これでは「武器」としてイマイチです。

そこでFOR文

下の行を繰り返して、「0,1」「0,2」「0,3」...とちまちまとコーディングしました。

grid.add(createImageLbl(lightGrass), 0, 1);

こんな感じで動きますが、如何せん汎用性に欠けていてまぁ使えないわけです。

FOR文を使うとこーなる

String lightGrass = "grass_light.png";
String deepGrass = "grass_deep.png";
String soilBasic = "soil_basic.png";
GridPane grid = new GridPane();
for (int i = 0; i < 4; i++) {
    grid.add(createImageLbl(lightGrass), 0, 1);
}
vBox.getChildren().add(grid);

これで緑の部分が1行分並びます。

FOR文の書き方

for (カウンター変数の初期化;論理式; 後処理)

【具体的なコード】

for (int i = 0; i < 5; i++) {
}

①「int i = 0」がカウンター変数の初期化になります。ループする度に後処理で「i」がカウントアップされます「i++」の処理です。

②1回ループすると論理式「i < 5」で、次のループを行うかどうか判定します。

③はじめのループでは「i = 0」なので「0 < 5」=TRUEですのでループが行われますが、「i = 5」になったら「5 < 5」=FALSEですのでループが行われません。

雑魚キャラが現れた!

おろ?なにが足りないのでしょうか?(不思議な設定をロード中です)

とりあえず言いたいことは20行くらいのコードが数行で片付きます。

(設定のロード完了)

たくのじ村では、ちょっと揉め事が起きていました。

「村人C」『中ボスを倒してもらうのに、こいつを渡そうと思ってたが〜のんに。。。だれら〜こんがーことやったのは?誰かなんとかしくんねぇかなぁ?』

「村人D」『俺じゃねーって!人のせいにすんなて〜』

「村人E」『いや、まずはこれをなんとしねぇば。。。あ、そこの人ちょっと頼みたい事がるんスけど。。。』

『組んであったFORが壊れているようで、こいつを直して頂きたいんす、いゃ自分はどーもよくわからないて。。。ギターなら弾けるんすけどね?』

今回のトラブル

上で紹介した、FOR文がうまく動いていません、本来ならば4x4のマスが並ぶはずですが、1行しか並んでいません。これをなんとか元に戻して頂きたいというわけです。

<ヒント>

現在は1行だけ並んでいますので、これを残り3行文を追加すればOKなのです。。。問題は「どーやるか?」です。

今回上に記載したコードはGitにコミットしてあるのでそれを直していただきたく。。。

でわでわ。。。

JavaFX ワンポイント 〜升目状にNodeを配置する〜

以下のような感じでNodeを配置できます。緑色の部分には50x50のラベル(Image付き)を4x4マスで並べました。

<ソース>

String lightGrass = "grass_light.png";
String deepGrass = "grass_deep.png";
String soilBasic = "soil_basic.png";
GridPane grid = new GridPane();
grid.add(createImageLbl(lightGrass), 0, 1);
grid.add(createImageLbl(lightGrass), 0, 2);
grid.add(createImageLbl(lightGrass), 0, 3);
grid.add(createImageLbl(lightGrass), 0, 4);
grid.add(createImageLbl(lightGrass), 1, 1);
grid.add(createImageLbl(lightGrass), 1, 2);
grid.add(createImageLbl(lightGrass), 1, 3);
grid.add(createImageLbl(lightGrass), 1, 4);
grid.add(createImageLbl(lightGrass), 2, 1);
grid.add(createImageLbl(lightGrass), 2, 2);
grid.add(createImageLbl(lightGrass), 2, 3);
grid.add(createImageLbl(lightGrass), 2, 4);
grid.add(createImageLbl(lightGrass), 3, 1);
grid.add(createImageLbl(lightGrass), 3, 2);
grid.add(createImageLbl(lightGrass), 3, 3);
grid.add(createImageLbl(lightGrass), 3, 4);
vBox.getChildren().add(grid);

lightGrass(ラベル, 位置(X), 位置(Y));のように設定します。

なので、上のソースを以下のように修正すると。。。

GridPane grid = new GridPane();
grid.add(createImageLbl(lightGrass), 0, 1);
grid.add(createImageLbl(lightGrass), 0, 2);
grid.add(createImageLbl(lightGrass), 0, 3);
grid.add(createImageLbl(lightGrass), 0, 4);
grid.add(createImageLbl(deepGrass), 1, 1);
grid.add(createImageLbl(deepGrass), 1, 2);
grid.add(createImageLbl(deepGrass), 1, 3);
grid.add(createImageLbl(deepGrass), 1, 4);
grid.add(createImageLbl(soilBasic), 2, 1);
grid.add(createImageLbl(lightGrass), 2, 2);
grid.add(createImageLbl(lightGrass), 2, 3);
grid.add(createImageLbl(lightGrass), 2, 4);
grid.add(createImageLbl(lightGrass), 3, 1);
grid.add(createImageLbl(soilBasic), 3, 2);
grid.add(createImageLbl(lightGrass), 3, 3);
grid.add(createImageLbl(lightGrass), 3, 4);
vBox.getChildren().add(grid);

座標で位置を示します。座標 = (X, Y) = (0, 1) => 0,1の位置テキストフィールドの下あたりにあります。

[rakuten ids="toripurussss:10000004"]

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

JavaFXでハローワールド〜OpenCVまで

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine〜

Git

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜


Stepup Programing〜 Java Fxで四則計算2〜

イントロダクション

前回は、クイズも交えて、入力コンポーネントを作成しました。

OpenCVは、画像解析用のライブラリです。輪郭の取り出しなど、いろいろできます。機械学習と連携して顔認証などにも応用されています。
以下の動画は、サンプルです。「OpenCVはこんな感じ・・・」というのがイメージできれば良いなと思いました。

OpenCvチュートリアルも詰まってきたので、基本に戻ります(笑)

<2019/02/09追記> 実装開始します。

計算処理

パソコンは大きな計算機です。なのでパソコンをコントロールするプログラムは計算処理が基本になる…と思いますが、どーですかね?

ジョークはさておきにして、今までに覚えた(理解した)事を整理します。

  1. ラベルに文字を表示する
  2. メソッドを呼ぶ(実装済のもの)
  3. テキストフィールドを追加する
  4. ラベルを追加する

こんな感じだと思います。※理解度は人によるので。。。

<余談>

何事も「すぐにわかる」とか「すぐ理解できる」というのは「能力」として良いものだと思いますが、それで人の優劣は決まりません。

実際に自分の場合は「なかなか理解できない」タイプの人間ですが今はプログラムを(後輩に)教えることの方が多いです。当時、一緒に学習していた、他の「すぐ理解できる」タイプの人たちは他のプログラム以外の仕事をしています。

Javaでの書き方

作成したプログラムは「myFirst Program()」と言うメソッドです。今度は、メソッドを自作します。メソッドの名前は「mySecondProgram()」です。メソッドの名前は頭文字を小文字にする「キャメルケース」と言う書き方をします。クラスは頭文字が大文字です。

これはJavaでのコーディングルール的なもので、世界の標準(Google、IBMなども採用してる)ものです。

こうすれば、一目でクラスとメソッド名の区別がつきます。ただし、変数名もキャメルケースなので、この部分は間違いやすいかも?

設計をする

プログラムの実装は、小さなサイクルで、設計〜実装〜テストを繰り返して行います。その内の、設計部分をやろうと言うわけです。

やりたい事を明確に

設計をする上でこれが凄く大事です。目的がはっきりしないと、コードもぐちゃぐちゃになります。なので、はじめの方に作成したコードは「リファクタリング」して整理しました。

<2019/02/09追記> しかし順序的にアレなんでリファクタリング前から開始します。(Gitソース)

とりあえずは、やりたい事(実現したい機能)を思い描きます。

やりたい事

今回は2つのテキストフィールドに値(数字)を入力してその計算結果をラベルに表示する。これが、やりたい事になります。

現状では入力後に計算するイベントを起こす物がないので計算ボタンを追加します。

そして、ボタンが押されたら計算処理を行い、結果をラベルに表示します。

やる事

  1. 計算ボタンを追加する
  2. ボタンが押されたら計算処理を行う
  3. 計算結果をラベルに表示する

<手順>

初めに現状の画面を確認します。下のような感じです。

「計算ボタンを追加する」下のような感じです。※イベント処理も追加してます。

イベント処理

ボタンにはsetOnActionと言うメソッドがあります。こいつを使って「ボタンが押されたら」の処理を行います。

とりあえず今回はここで終わります。

イベント処理は「(ボタンが)押下されたら」「ボタンが離されたら」。。。と色々ありますが、今回の使用したイベントは「Action」です、これはまとめた言い方(実装)です。「アクションがあった時」というイベントに反応して起動するものになります。書き方は下のような感じです。

Button keisan = new Button("計算");
keisan.setOnAction(new EventHandler<ActionEvent>() { ... });

後ほど実装などについて追記します。GITソース

今回の中ボス

「中ボス」という表現をしましたが、「目玉」です。イベント処理の実装部分です。今回は工夫をしないで、ストレートにずらずらとコードを書きました。

自分がコード・レビューをすると、言いたいことが「まぁまぁ」あります。そのうちの1つは「コードが汚い!」ということです。

中ボスの正体

  1. コードが汚いので綺麗で見やすいコードにしたい。
  2. テキストフィールドに「数字」以外は入っている時に「Hello World」の部分にエラーメッセージを表示しているが、チェックを入れるようにしたい。
  3. 足し算しかできないので他の計算もしたい。

村人Aの話

「たくのじ村」に住んでいる村人Aの話です。(そういう設定(笑))

『上にあげたような問題(中ボス)がいてほとほと困っておりますこって。だっけなんとかやっつけてもらえねぇでしょうか?奴はGITにコミットされてるすけ〜PULLなりダウンロードするなりして、やっつけておくんなせぇ』

こちらが問題のソースです。

でわでわ。。。

<<< 前回 次回 >>>

JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜

FXMLで追加したボタンに。。。

onAction属性でメソッドを割り当てる。

<FXML>コピーして作成したファイルを開くと上のような画面が見れます。

<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.*?>
<BorderPane prefHeight="186.0" prefWidth="562.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="zenryokuservice.opencv.fx.tutorial2.FourierController">
<left>
<VBox alignment="CENTER">
<padding>
<Insets left="10" right="10" />
</padding>
   <children>
   <ImageView fx:id="originalImage" />
   </children>
</VBox>
</left>
<right>
<VBox alignment="CENTER" spacing="10">
<padding>
<Insets left="10" right="10" />
</padding>
   <children>
   <ImageView fx:id="transformedImage" />
   <ImageView fx:id="antitransformedImage" />
   </children>
</VBox>
</right>
<bottom>
<HBox alignment="CENTER" prefHeight="77.0" prefWidth="582.0" spacing="10">
<padding>
<Insets bottom="25" left="25" right="25" top="25" />
</padding>
   <children>
   <Button alignment="center" onAction="#loadImage" text="Load Image" />
   <Button fx:id="transformButton" alignment="center" disable="true" onAction="#transformImage" prefHeight="27.0" prefWidth="110.0" text="Apply transformation" />
   <Button fx:id="antitransformButton" alignment="center" disable="true" onAction="#antitransformImage" prefHeight="27.0" prefWidth="94.0" text="Apply anti transformation" />
            <Button fx:id="exeButton" mnemonicParsing="false" text="Execute" onAction="#execute" />
            <SplitMenuButton fx:id="selectorBox" mnemonicParsing="false" prefHeight="27.0" prefWidth="93.0" text="Method">
              <items>
                <MenuItem mnemonicParsing="false" text="Action 1" />
                <MenuItem mnemonicParsing="false" text="Action 2" />
              </items>
            </SplitMenuButton>
   </children>
</HBox>
</bottom>
   <top>
      <Label fx:id="messageLbl" alignment="TOP_CENTER" prefHeight="19.0" prefWidth="361.0" textAlignment="CENTER" BorderPane.alignment="CENTER" />
   </top>
</BorderPane>

上の赤い字の部分が追加したコンポーネントです。対象はボタンのみです。

<対象のボタン>

@FXML
private Button exeButton;

<そして対応するメソッド>

/**
* FXMLファイルにこのメソッドをonAction属性に指定している。
*/
@FXML
public void execute() {
System.out.println("Hello JavaFX");
}

<実行結果>

[rakuten ids="dtc:11465875"]

関連ページ一覧

  1. EclipseにSceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  4. ステップアッププログラミング〜Java FxでHelloWorld解説〜

開発環境構築

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. Java OpenCV 環境セットアップ(on Mac)
  3. Eclipse SceneBuilderを追加する
  4. JavaFX SceneBuilder EclipseSceneBuilder連携~