├── .gitignore ├── .idea ├── .gitignore ├── artifacts │ └── CurrencyConverterApp.xml ├── compiler.xml ├── description.html ├── encodings.xml ├── gradle.xml ├── libraries │ ├── json_20201115.xml │ └── lib.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── CurrencyConverterApp.iml ├── README.md ├── screens ├── AcnhorPane.PNG ├── Artifacts.PNG ├── GridPane.png ├── Properties.PNG ├── empty_text.PNG ├── empty_window.PNG ├── example.PNG ├── exe1.PNG ├── exe2.PNG ├── final_layout.PNG ├── fx_id.PNG ├── java8.PNG ├── skeleton.PNG └── sout_itworks.PNG └── src ├── META-INF └── MANIFEST.MF └── sample ├── Controller.java ├── Main.java └── sample.fxml /.gitignore: -------------------------------------------------------------------------------- 1 | /out -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/artifacts/CurrencyConverterApp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/CurrencyConverterApp 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple JavaFX 2.0 application that includes simple .fxml file with attached controller and Main class to quick start. Artifact to build JavaFX application is provided. 2 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/libraries/json_20201115.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/libraries/lib.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CurrencyConverterApp.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building desktop app (.exe) with JavaFX 2 | ## Introduction 3 | In this guide, you will learn how to build an executable **JavaFX** desktop application and later can run it without IDE by just clicking *.exe* file. 4 | The problem with JavaFX is that Oracle is ruining this awesome tool by making it harder to execute on JDK 11, but referencing this [link](https://stackoverflow.com/questions/61555515/intellij-idea-javafx-export-cant-build-artifact-fxdeploy-is-not-available) I have just chosen to download JDK 8 since it is building JavaFX without any issues. 5 | ## Install JDK 8 6 | To do that go [there](https://docs.aws.amazon.com/corretto/latest/corretto-8-ug/downloads-list.html) and download a particular version for your OS 7 | ## Install SceneBuilder for building GUI for our app 8 | Go to the [site](https://gluonhq.com/products/scene-builder/) and download the app. 9 | ## Download JavaFX 10 | Go to the [site](https://gluonhq.com/products/javafx/) and download JavaFX Windows SDK. 11 | Then you unzip in your chosen directory. You will source this for each JavaFX project. (Unfortunately each time the same steps). 12 | 13 | ## Run your first JavaFX app via IntelliJ 14 | 1. Click **[+ New Project]** -> **[Java FX]** -> **[Project SDK]** -> **[Corretto-11 java version “11.0.8”]** -> **[Next]** -> **[Name and propject location]** -> **[Finish]** 15 | 2. Go to **[File]** -> **[Project Structure…]** *or Ctr+Alt+Shift+S* -> **[Libraries]** -> **[New Project Library (+) sign]** -> **[Java]** -> **[Choose the directory of unzipped SDK folder lib]** -> **[Press okay]** 16 | 3. Go to **[Run]** -> In Application/Main in *Configuration* tab under field **[VM Options:]** you have to place the following fields: 17 | ```shell 18 | --module-path \javafx-sdk-11.0.2\lib --add-modules javafx.controls,javafx.fxml 19 | ``` 20 | Instead of *\javafx-sdk-11.0.2\lib* you need to set your own directory of JavaFX lib folder. 21 | 22 | 4. Run (shift + f10) Main.java and you will see this window if you do all these steps correctly. 23 | ![empty_window](screens/empty_window.PNG) 24 | 25 | ## Build a JavaFX app with SceneBuilder 26 | For the sake of simplicity, I will build a simple currency converter app which will use API. 27 | ![example](screens/example.PNG) 28 | 1. Open SceneBuilder 29 | 2. Choose **Open Project** 30 | 3. Find in a directory of the app (in src folder) **.fxml** file and open it 31 | 4. For the moment we will drop default GridPane (0x0) 32 | ![gridpane](screens/GridPane.png) 33 | 5. Drag AnchorPane and move to the main screen. This is the main window of our application. 34 | ![anchorpane](screens/AcnhorPane.PNG) 35 | 6. We can adjust the size of the window as well as colour and style if you are familiar with *CSS* 36 | 7. We can use the search window to quickly find an object, for example, “Text”. Drag to the main screen and adjust the size of Text area and styling. 37 | ![text_style](screens/Properties.PNG) 38 | 8. Then keep filling like you wish the App. And at the end, the layout should look similar to this: 39 | ![final_layout](screens/final_layout.PNG) 40 | 41 | You now can preview the app, go to **[Preview]** -> **[Show Preview in Window]** or simply *Ctrl+P* 42 | Now steps to use this template in our app as well as set-up IDs for further uses. 43 | 1. To further use an object in code and provide the reactivity for that we need to set **fx:id**. Select the object and on the right side of the SceneBuilder click tab **[Code]**. You will see the **fx:id** fill the id of the object. Place IDs for other objects. 44 | ![fx_id](screens/fx_id.PNG) 45 | 2. I built three empty text objects and assign **fx:id** for them to display the information about currency rate; conversion and date when button “Convert” is clicked. 46 | ![empty_text](screens/empty_text.PNG) 47 | 3. In button left side click **[Controller]** and in field **[Contoller class]** and provide the root to Controller.java. For example **[sample.Controller]** 48 | ![fx_id](screens/fx_id.PNG) 49 | 4. After previous steps, we save the changes (Ctrl + S) it will replace **.fxml** layout to our built layout in SceneBuilder. 50 | 5. Finally, we need to click **[View]** -> **[Show Sample Controller Skeleton]** -> click in right button **[Full]** then Copy and paste in the app directory *Controller.java* 51 | ![skeleton](screens/skeleton.PNG) 52 | I got something like this: 53 | ```Java 54 | package sample; 55 | 56 | import java.net.URL; 57 | import java.util.ResourceBundle; 58 | import javafx.fxml.FXML; 59 | import javafx.scene.control.Button; 60 | import javafx.scene.control.TextField; 61 | import javafx.scene.text.Text; 62 | 63 | public class Controller { 64 | 65 | @FXML 66 | private ResourceBundle resources; 67 | 68 | @FXML 69 | private URL location; 70 | 71 | @FXML 72 | private TextField amountField; 73 | 74 | @FXML 75 | private TextField ccyOne; 76 | 77 | @FXML 78 | private TextField ccyTwo; 79 | 80 | @FXML 81 | private Button applyBtn; 82 | 83 | @FXML 84 | private Text rateCcy; 85 | 86 | @FXML 87 | private Text conversionTotal; 88 | 89 | @FXML 90 | private Text dateStamp; 91 | 92 | @FXML 93 | void initialize() { 94 | assert amountField != null : "fx:id=\"amountField\" was not injected: check your FXML file 'sample.fxml'."; 95 | assert ccyOne != null : "fx:id=\"ccyOne\" was not injected: check your FXML file 'sample.fxml'."; 96 | assert ccyTwo != null : "fx:id=\"ccyTwo\" was not injected: check your FXML file 'sample.fxml'."; 97 | assert applyBtn != null : "fx:id=\"applyBtn\" was not injected: check your FXML file 'sample.fxml'."; 98 | assert rateCcy != null : "fx:id=\"rateCcy\" was not injected: check your FXML file 'sample.fxml'."; 99 | assert conversionTotal != null : "fx:id=\"conversionTotal\" was not injected: check your FXML file 'sample.fxml'."; 100 | assert dateStamp != null : "fx:id=\"dateStamp\" was not injected: check your FXML file 'sample.fxml'."; 101 | 102 | } 103 | } 104 | 105 | ``` 106 | ## Coding application 107 | Firstly, let's quickly fix **Main.java**: 108 | 1. Set title: ``primaryStage.setTitle("Currency Converter");`` 109 | 2. Place size from SceneBuilder in object **Scene**: 110 | `` primaryStage.setScene(new Scene(root, 384, 283));`` 111 | 3. Fix the window to not be scaled: 112 | ``primaryStage.setResizable(false);`` 113 | 114 | Now we can go to Contoller.java and do all work there. 115 | There you could see the ``initialize()``. From this method we can drop warnings and rewrite the code to check is our template is functional or not. Let’s just add **sout** command to get output in the console by clicking the button: 116 | 117 | ```Java 118 | @FXML 119 | void initialize() { 120 | applyBtn.setOnAction(event -> { 121 | System.out.println("IT WORKS!"); 122 | }); 123 | } 124 | ``` 125 | 126 | ![itworks](screens/sout_itworks.PNG) 127 | 128 | You might notice the red warning. This is because of compitability issues of JavaFX. Just go to **.fxml** file in **AnchorPane** and replace ``xmlns="http://javafx.com/javafx/15.0.1"`` to which version it asks (``xmlns="http://javafx.com/javafx/11.0.2"``) 129 | 130 | ## Install jar for JSON Parsing 131 | Next let's install JSON jar from [here](https://mvnrepository.com/artifact/org.json/json/20201115) or [here](https://repo1.maven.org/maven2/org/json/json/20201115/json-20201115.jar). Store it in any directory and go to **[File]** -> **[Project Structure…]** *or Ctr+Alt+Shift+S* -> **[Libraries]** -> **[New Project Library (+) sign]** -> **[Java]** -> **[Choose jar file]** -> **[Press okay]** 132 | 133 | ## Working with API 134 | you actually can do any other API if you like. I choose first [link](https://currencylayer.com/) in google. I won't explain how to set-up - it is easy. But once you logged in go to how to start and find the api link with your assigned token like i did http://data.fixer.io/api/latest?access_key=27ad197ccf98251c14ebc0b13134de39&symbols=USD 135 | Even if you click this link it will open JSON object in your browser, so we can now use it in our application. 136 | 137 | Before we need to build a class **getUrlContent** which will buffer data from the GET. 138 | 139 | ```Java 140 | private static String getUrlContent(String urlAddress) { 141 | StringBuffer content = new StringBuffer(); 142 | try { 143 | URL url = new URL(urlAddress); 144 | URLConnection urlConn = url.openConnection(); 145 | 146 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); 147 | String line; 148 | while ((line = bufferedReader.readLine()) != null) { 149 | content.append(line + "\n"); 150 | } 151 | bufferedReader.close(); 152 | } catch (Exception e) { 153 | System.out.println("Error in conversion"); 154 | } 155 | return content.toString(); 156 | } 157 | ``` 158 | 159 | Now in the method **initialize()** we can build up our parser and output insted of sout function: 160 | 161 | ```Java 162 | @FXML 163 | void initialize() { 164 | applyBtn.setOnAction(event -> { 165 | String output = getUrlContent("http://data.fixer.io/api/latest?access_key=" + 166 | "27ad197ccf98251c14ebc0b13134de39&symbols="+ccyOne.getText().toUpperCase()+","+ccyTwo.getText().toUpperCase()); 167 | if(!output.isEmpty()) { 168 | JSONObject obj = new JSONObject(output); 169 | dateStamp.setText(obj.getString("date")); 170 | double ccyTwoValue = obj.getJSONObject("rates").getDouble(ccyTwo.getText()) / 171 | obj.getJSONObject("rates").getDouble(ccyOne.getText()); 172 | String ccyTwoStr = String.format("%.2f", ccyTwoValue) + " " + ccyTwo.getText(); 173 | 174 | rateCcy.setText(ccyTwoStr); 175 | 176 | double amount = Double.parseDouble(amountField.getText()); 177 | double total = ccyTwoValue * amount; 178 | String totalStr = String.format("%.2f", total) + " " + ccyTwo.getText(); 179 | conversionTotal.setText(totalStr); 180 | } 181 | }); 182 | } 183 | ``` 184 | 185 | And finally if it works then you can convert any currency and amount you would like. 186 | 187 | ### !!! Be awere to use indexes for currncy like EUR - for euro or USD - for US Dollar. 188 | 189 | ## Build a self contained .exe file 190 | If everything works then we can finally build our application as .exe file to use it without IDE. 191 | 1. Go to **[File]** -> **[Project Structure…]** *or Ctr+Alt+Shift+S* -> **[Project]** -> set Project as 1.8 and project language level as 8 ![java8](screens/java8.PNG) 192 | 2. Go to **[Artifacts]** -> **+ Add** or Alt+Insert -> **JavaFX Application** -> **From module..**. 193 | 3. In output tab move JSON jar and lib from JavaFX to the left into .jar of your project ![Artifacts](screens/Artifacts.PNG) 194 | 4. Go to tab **Java FX** in **Application class:** set your main class or click folder icon and choose, for example *sample.Main*, in **Native bundle:** choose all option and press ok. 195 | 5. Go to **[Build]** -> **[Build Artifacts..]** 196 | 197 | If there is no errors it should create in **out.artifacts** folder bundle. Go there and you will the last folder where is .exe file. You can move this folder out of directory and it can works without IDE. 198 | ![exe](screens/exe1.PNG) 199 | 200 | ![exe2](screens/exe2.PNG) 201 | -------------------------------------------------------------------------------- /screens/AcnhorPane.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/AcnhorPane.PNG -------------------------------------------------------------------------------- /screens/Artifacts.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/Artifacts.PNG -------------------------------------------------------------------------------- /screens/GridPane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/GridPane.png -------------------------------------------------------------------------------- /screens/Properties.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/Properties.PNG -------------------------------------------------------------------------------- /screens/empty_text.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/empty_text.PNG -------------------------------------------------------------------------------- /screens/empty_window.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/empty_window.PNG -------------------------------------------------------------------------------- /screens/example.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/example.PNG -------------------------------------------------------------------------------- /screens/exe1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/exe1.PNG -------------------------------------------------------------------------------- /screens/exe2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/exe2.PNG -------------------------------------------------------------------------------- /screens/final_layout.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/final_layout.PNG -------------------------------------------------------------------------------- /screens/fx_id.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/fx_id.PNG -------------------------------------------------------------------------------- /screens/java8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/java8.PNG -------------------------------------------------------------------------------- /screens/skeleton.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/skeleton.PNG -------------------------------------------------------------------------------- /screens/sout_itworks.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifarkhshatov/JavaFX-Tutorial/2eacb04075b5c8682f87968386045c334b984eaf/screens/sout_itworks.PNG -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: sample.Main 3 | 4 | -------------------------------------------------------------------------------- /src/sample/Controller.java: -------------------------------------------------------------------------------- 1 | 2 | package sample; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.InputStreamReader; 6 | import java.net.URL; 7 | import java.net.URLConnection; 8 | import java.util.ResourceBundle; 9 | import javafx.fxml.FXML; 10 | import javafx.scene.control.Button; 11 | import javafx.scene.control.TextField; 12 | import javafx.scene.text.Text; 13 | import org.json.JSONObject; 14 | 15 | public class Controller { 16 | 17 | @FXML // ResourceBundle that was given to the FXMLLoader 18 | private ResourceBundle resources; 19 | 20 | @FXML // URL location of the FXML file that was given to the FXMLLoader 21 | private URL location; 22 | 23 | @FXML // fx:id="amountField" 24 | private TextField amountField; // Value injected by FXMLLoader 25 | 26 | @FXML // fx:id="ccyOne" 27 | private TextField ccyOne; // Value injected by FXMLLoader 28 | 29 | @FXML // fx:id="ccyTwo" 30 | private TextField ccyTwo; // Value injected by FXMLLoader 31 | 32 | @FXML // fx:id="applyBtn" 33 | private Button applyBtn; // Value injected by FXMLLoader 34 | 35 | @FXML // fx:id="rateCcy" 36 | private Text rateCcy; // Value injected by FXMLLoader 37 | 38 | @FXML // fx:id="conversionTotal" 39 | private Text conversionTotal; // Value injected by FXMLLoader 40 | 41 | @FXML // fx:id="dateStamp" 42 | private Text dateStamp; // Value injected by FXMLLoader 43 | 44 | @FXML // This method is called by the FXMLLoader when initialization is complete 45 | void initialize() { 46 | applyBtn.setOnAction(event -> { 47 | String output = getUrlContent("http://data.fixer.io/api/latest?access_key=" + 48 | "27ad197ccf98251c14ebc0b13134de39&symbols="+ccyOne.getText().toUpperCase()+","+ccyTwo.getText().toUpperCase()); 49 | if(!output.isEmpty()) { 50 | JSONObject obj = new JSONObject(output); 51 | dateStamp.setText(obj.getString("date")); 52 | double ccyTwoValue = obj.getJSONObject("rates").getDouble(ccyTwo.getText()) / 53 | obj.getJSONObject("rates").getDouble(ccyOne.getText()); 54 | String ccyTwoStr = String.format("%.2f", ccyTwoValue) + " " + ccyTwo.getText(); 55 | 56 | rateCcy.setText(ccyTwoStr); 57 | 58 | double amount = Double.parseDouble(amountField.getText()); 59 | double total = ccyTwoValue * amount; 60 | String totalStr = String.format("%.2f", total) + " " + ccyTwo.getText(); 61 | conversionTotal.setText(totalStr); 62 | } 63 | }); 64 | } 65 | private static String getUrlContent(String urlAddress) { 66 | StringBuffer content = new StringBuffer(); 67 | try { 68 | URL url = new URL(urlAddress); 69 | URLConnection urlConn = url.openConnection(); 70 | 71 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); 72 | String line; 73 | while ((line = bufferedReader.readLine()) != null) { 74 | content.append(line + "\n"); 75 | } 76 | bufferedReader.close(); 77 | } catch (Exception e) { 78 | System.out.println("Error in conversion"); 79 | } 80 | return content.toString(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/sample/Main.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import javafx.application.Application; 4 | import javafx.fxml.FXMLLoader; 5 | import javafx.scene.Parent; 6 | import javafx.scene.Scene; 7 | import javafx.stage.Stage; 8 | 9 | public class Main extends Application { 10 | 11 | @Override 12 | public void start(Stage primaryStage) throws Exception{ 13 | Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); 14 | primaryStage.setTitle("Currency Converter"); 15 | primaryStage.setScene(new Scene(root, 363, 263)); 16 | primaryStage.setResizable(false); 17 | primaryStage.show(); 18 | } 19 | 20 | 21 | public static void main(String[] args) { 22 | launch(args); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/sample/sample.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | --------------------------------------------------------------------------------