はじめに
この記事はleJOSの開発環境が整っていることが前提にしています。
詳しくはこちらの記事を参考にして下さい。
概要
この記事は以下の記事の続編となっています。leJOSのリモートコントロール用クラスremoteEv3とJavaFxを使ってEv3を制御するGUIアプリケーションの開発を解説します。
今回作成したものは簡単なラジコンアプリです。
(クリックで動画再生)
プログラム
ファイル構成は次のようになっています。
プロジェクト名はJavaFxEv3としました。
Form.fxml
ここにGUIを記述します。SceneBuilderを使って編集できます。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.FormController">
<children>
<Button fx:id="LeftButton" layoutX="100.0" layoutY="180.0" mnemonicParsing="false" onMousePressed="#LeftButtonPressed" onMouseReleased="#LeftButtonReleased" prefHeight="40.0" prefWidth="100.0" text="Left" />
<Button fx:id="RightButton" layoutX="400.0" layoutY="180.0" mnemonicParsing="false" onMousePressed="#RightButtonPressed" onMouseReleased="#RightButtonReleased" prefHeight="40.0" prefWidth="100.0" text="Right" />
<Button fx:id="ForwardButton" layoutX="250.0" layoutY="62.0" mnemonicParsing="false" onMousePressed="#ForwardButtonPressed" onMouseReleased="#ForwardButtonReleased" prefHeight="40.0" prefWidth="100.0" text="Forward" />
<Button fx:id="BackwardButton" layoutX="250.0" layoutY="300.0" mnemonicParsing="false" onMousePressed="#BackwardButtonPressed" onMouseReleased="#BackwardButtonReleased" prefHeight="40.0" prefWidth="100.0" text="Backward" />
</children>
</Pane>
解説
それぞれのボタンにマウスで押された時と、マウスが離れた時に呼ばれるメソッドを登録しています。onMousePressedにボタンが押された時のメソッド、onMouseReleasedにボタンが離された時のメソッドを登録します。
application.css
GUIのスタイルを設定できます。
/* 背景色の設定 */
.root{
-fx-background-color: white;
}
/* ボタンの色設定 */
.button {
-fx-background-color: slateblue; -fx-text-fill: white;
}
/* ボタンマウスオーバー時の色設定 */
.button:hover{
-fx-background-color: green; -fx-text-fill: white;
}
Main.java
package application;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import lejos.remote.ev3.RMIRegulatedMotor;
import lejos.remote.ev3.RemoteEV3;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
public RemoteEV3 ev3 = null;
public RMIRegulatedMotor leftMotor = null;
public RMIRegulatedMotor rightMotor = null;
@Override
public void start(Stage primaryStage) {
try {
//リモートコントロールのためのインスタンス生成
ev3 = new RemoteEV3("192.168.2.91");
ev3.setDefault();
//モーターオブジェクト作成
leftMotor = ev3.createRegulatedMotor("A", 'L');
rightMotor = ev3.createRegulatedMotor("B", 'L');
} catch (RemoteException | MalformedURLException | NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Form.fxml"));
Pane root = (Pane)loader.load();
Scene scene = new Scene(root,600,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
//コントローラにモーターオブジェクトを渡す
FormController controller = loader.getController();
controller.setThisLeftMotor(leftMotor);
controller.setThisRightMotor(rightMotor);
//画面表示
primaryStage.setScene(scene);
primaryStage.show();
//画面が閉じられた時の処理
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
System.out.println("Stage is closing");
try {
leftMotor.close();
rightMotor.close();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
解説
RemoteEv3クラスを使ってモーターにアクセスするオブジェクトを作成します。
ev3 = new RemoteEV3("192.168.2.91");
ev3.setDefault();
//モーターオブジェクト作成
leftMotor = ev3.createRegulatedMotor("A", 'L');
rightMotor = ev3.createRegulatedMotor("B", 'L');
モーターオブジェクトをコントローラに渡します。
//コントローラにモーターオブジェクトを渡す
FormController controller = loader.getController();
controller.setThisLeftMotor(leftMotor);
controller.setThisRightMotor(rightMotor);
プログラム終了時にモーターへのアクセスを閉じるようにします。これを設定しないとプログラムを再度起動した際にエラーが起きてしまいます。
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
System.out.println("Stage is closing");
try {
leftMotor.close();
rightMotor.close();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
FormController.java
コントローラ部分です。GUIとメソッドを関連付けします。
package application;
import java.rmi.RemoteException;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import lejos.remote.ev3.RMIRegulatedMotor;
public class FormController {
public RMIRegulatedMotor thisLeftMotor = null;
public RMIRegulatedMotor thisRightMotor = null;
public void setThisLeftMotor(RMIRegulatedMotor leftMotor) {
thisLeftMotor = leftMotor;
}
public void setThisRightMotor(RMIRegulatedMotor rightMotor) {
thisRightMotor = rightMotor;
}
@FXML
Button LeftButton;
@FXML
Button RightButton;
@FXML
Button ForwardButton;
@FXML
Button BackwardButton;
@FXML
void initialize() {
System.out.println("初期化処理");
}
@FXML
public void LeftButtonPressed(MouseEvent actionEvent) {
try {
thisLeftMotor.forward();
thisRightMotor.backward();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void LeftButtonReleased(MouseEvent actionEvent) {
try {
thisLeftMotor.stop(true);
thisRightMotor.stop(true);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void RightButtonPressed(MouseEvent actionEvent) {
try {
thisLeftMotor.backward();
thisRightMotor.forward();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void RightButtonReleased(MouseEvent actionEvent) {
try {
thisLeftMotor.stop(true);
thisRightMotor.stop(true);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void ForwardButtonPressed(MouseEvent actionEvent) {
try {
thisLeftMotor.forward();
thisRightMotor.forward();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void ForwardButtonReleased(MouseEvent actionEvent) {
try {
thisLeftMotor.stop(true);
thisRightMotor.stop(true);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void BackwardButtonPressed(MouseEvent actionEvent) {
try {
thisLeftMotor.backward();
thisRightMotor.backward();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void BackwardButtonReleased(MouseEvent actionEvent) {
try {
thisLeftMotor.stop(true);
thisRightMotor.stop(true);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
解説
コントローラ内からモーターオブジェクトにアクセスするためにセッターを定義します。
public void setThisLeftMotor(RMIRegulatedMotor leftMotor) {
thisLeftMotor = leftMotor;
}
public void setThisRightMotor(RMIRegulatedMotor rightMotor) {
thisRightMotor = rightMotor;
}
例えば以下のコードではLeftButtonが押された時に呼び出されるLeftButtonPressedメソッド、LeftButtonが離された時に呼び出されるLeftButtonReleasedメソッドを定義しています。
@FXML
public void LeftButtonPressed(MouseEvent actionEvent) {
try {
thisLeftMotor.forward();
thisRightMotor.backward();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@FXML
public void LeftButtonReleased(MouseEvent actionEvent) {
try {
thisLeftMotor.stop(true);
thisRightMotor.stop(true);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
まとめ
JavaFxとleJOSのRemoteEv3クラスを使ったGUIアプリの開発方法を紹介しました。
これを使えばセンサー値を取得してGUI上に可視化するといったこともできるでしょう。
RemoteEv3クラスに関してはこちらの記事も参考にして下さい。