How do i start a JavaFX GUI in an own thread - java

I have a Project, where I need to start a GUI but in another thread that is not my main thread.
-> The first main thread starts...
-> If it decides to show a GUI it starts my GUI.
-> All other calculations should still happen in the main thread.
What I mean with this is, that i can't, ounder no circumstance, start the gui in the main thread. And i need to be able to comunicate with my Controller (no controller in the sample). But when i do the normal: .. Start extends Application { .. approach, I cant communicate with the controller anymore because the thread is occupied. The code below should allow me to do everything I need to do, so I hope there is a way I can make it work.
The problem, why my code doesn't work is a Exception:
Exception in thread "Thread-0" java.lang.IllegalStateException: Toolkit not initialized
When calling Platform.runLater() .. in my GuiThread class.
Thanks four your help in advance.
My main class:
public class Start{
private void start() {
GuiThread thread = new GuiThread();
thread.start();
System.out.println("here continues the thread, while the GUI is shown");
}
public static void main(String[] args) {
Start main = new Start();
main.start();
}
}
My custom thread class, where my GUI should be started:
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class GuiThread extends Thread {
#Override
public void run() {
super.run();
// Here i have objects i need to have in the controller
// Then i have to start my GUI
// When calling Platform.runLater()... this error shows : Exception in thread "Thread-0" java.lang.IllegalStateException: Toolkit not initialized
Platform.runLater(() -> {
Group root;
try {
Stage stage = new Stage();
root = new Group();
Scene scene = new Scene(root);
FXMLLoader loader = new FXMLLoader(getClass().getResource("myGui.fxml"));
Node node = loader.load();
// Controller stuff
root.getChildren().add(node);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
Just a sample FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<StackPane prefHeight="150.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
<children>
<Label text="left" />
</children>
</StackPane>
<StackPane prefHeight="150.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
<children>
<Label text="right" />
</children>
</StackPane>
</children>
</HBox>

Usually you'd start any additional threads from the Application.init or Application.start methods, but in your case this doesn't seem to be an option.
Starting with JavaFX 9 you could use Platform.startup the first time you need access to JavaFX. After the Runnable passed to that method is executed you should be able to use Platfrom.runLater as you're used to.
Using this approach you need to make sure to shut when all other logic has completed and you're sure you don't need to display any GUI.
Platform.startup(() -> {
Group root;
try {
Stage stage = new Stage();
root = new Group();
Scene scene = new Scene(root);
FXMLLoader loader = new FXMLLoader(getClass().getResource("myGui.fxml"));
Node node = loader.load();
// Controller stuff
root.getChildren().add(node);
stage.setScene(scene);
stage.setOnHidden(evt -> Platform.exit()); // make sure to completely shut down JavaFX when closing the window
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
});

Related

How do I replace an ImageView with a label at the click of a button and then return the ImageView back?

I have a no internet scene with an ImageView and a button, I need to replace the ImageView by a Label when the button is pressed, and after checking the internet if there is no internet, return the ImageView back.
The problem is that there is no element change in the application and the picture remains static, the Label doesn't even appear for seconds.
My code:
MainApplication.java
package com.streamvoice;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import scripts.streamvoice.Scripts;
public class MainApplication extends Application {
Scripts scripts = new Scripts();
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader;
if (scripts.isConnection()) {
fxmlLoader = new FXMLLoader(getClass().getResource("StartScene.fxml"));
}
else {
fxmlLoader = new FXMLLoader(getClass().getResource("ConnectionErrorScene.fxml"));
}
Scene scene = new Scene(fxmlLoader.load(), 1000, 500);
stage.setTitle("Stream Voice");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
ConnectionErrorScene.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="mVBox" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.streamvoice.ConnectionSceneController">
<children>
<ImageView fx:id="mErrorImage" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../images/connectionError.png" />
</image>
</ImageView>
<ProgressIndicator progress="0.0" />
<Button fx:id="mTryConnectButton" mnemonicParsing="false" onAction="#tryConnect" text="try" />
</children>
</VBox>
ConnectionSceneController.java
package com.streamvoice;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import scripts.streamvoice.Scripts;
public class ConnectionSceneController {
Scripts scripts = new Scripts();
#FXML private Button mTryConnectButton;
#FXML private ImageView mErrorImage;
#FXML private ProgressIndicator mConnectionProgressIndicator; //Затычка
#FXML private VBox mVBox;
private void tryConnect() {
Label labelLoadAnimation = new Label("testText");
mVBox.getChildren().set(0, labelLoadAnimation);
if (scripts.isConnection())
{
mVBox.getChildren().set(0, mErrorImage);
}
}
}
Assuming scripts.isConnection() is a long-running process, executing it on the FX Application Thread will prevent the window from being redrawn until it completes.
At an intuitive level, the FX Application Thread executes a loop that does something like this:
while the application is running:
if there are user events to handle:
handle user events
if there are animations active:
update animations
if there are pending runnables in Platform.runLater(), execute them
if it is time to repaint the scene:
if there are changes to the scene:
recompute layout and repaint scene
Therefore, if you execute a long-running process on the FX Application Thread (e.g. in an event handler or in a Runnable
passed to Platform.runLater()), this loop will not get to repaint the scene until that process is complete.
You need to run the long running process on a background thread. You can use the Task API to do this:
private void tryConnect() {
Label labelLoadAnimation = new Label("testText");
mVBox.getChildren().set(0, labelLoadAnimation);
Task<Boolean> testConnectionTask = new Task<>() {
#Override
public Boolean call() throws Exception {
return scripts.isConnection();
}
};
testConnectionTask.setOnSucceeded(e -> {
if (testConnectionTask.getValue()) {
mVBox.getChildren().set(0, mErrorImage);
}
}
Thread thread = new Thread(testConnectionTask);
thread.start();
}

Consuming onCloseRequest event of tab disables the tab completely

I am writing an in-app web browser for a JavaFX application which as all browsers, has tabs. The structure of the whole app is based on a TabPane in which all of the functionality of the app is shown. When the user selects to use the browser, a new Tab (let's call it browserMainTab) is created, and it contains another TabPane for the browser tabs. I would like to show a confirmation dialog when the user selects to close the browserMainTab but the inner TabPane still has opened tabs. So far, evertyhing is ok, but when I consume the onCloseRequest event of browserMainTab the tab stays still active with all its' children but it can't be clicked, dragged, or closed.
private void mainBrowserTabCloseConfirmationEvent(Tab tab){
tab.setOnCloseRequest(event -> {
AnchorPane pane = (AnchorPane) tab.getContent();
TabPane browserSubTabPane = (TabPane) pane.getChildren().get(0);
if(browserSubTabPane.getTabs().size() >= 1){
StillOpenBrowserTabsAlert alert = new StillOpenBrowserTabsAlert();
alert.setNumOfOpenTabs(browserSubTabPane.getTabs().size());
Alert alert1 = alert.alertWithReturnType();
if(alert1.getResult() == ButtonType.OK){
getMainTabPane().getTabs().remove(getMainTabPane()
.getSelectionModel()
.getSelectedItem());
}else{
event.consume();
}
}
});
}
The above snippet throws no exceptions, and the first part works fine. The issue comes up after I consume() the event, when the tab becomes unclickable. Can somebody help please?
**EDIT**
Reproducible example as requested
ExampleMain.java:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ExampleMain extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("mainTabPane.fxml"));
Parent root = loader.load();
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
}
MainTabPane.java
package sample;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainTabPane implements Initializable {
#FXML private TabPane mainTabPane;
private SubTabPane subTabPaneController;
private SubTabPane getSubTabPaneController() {
return subTabPaneController;
}
private void setSubTabPaneController(SubTabPane subTabPaneController) {
this.subTabPaneController = subTabPaneController;
}
private TabPane getMainTabPane() { return mainTabPane; }
private void loadSubTabPaneAsTabContent(){
FXMLLoader loader = new FXMLLoader(getClass().getResource("subTabPane.fxml"));
Parent root = null;
try{
root = loader.load();
}catch (IOException exception){
exception.printStackTrace();
}
assert root != null;
setSubTabPaneController(loader.getController());
Tab tab = new Tab("Tab of main TabPane");
tab.setContent(root);
getMainTabPane().getTabs().add(tab);
closeRequestOfMainTabPane(tab);
}
private void closeRequestOfMainTabPane(Tab tab){
tab.setOnCloseRequest(e -> {
int numOfOpenTabsInSubTabPane = getSubTabPaneController().getSubTabPane().getTabs().size();
if(numOfOpenTabsInSubTabPane >= 1){
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.showAndWait();
if(alert.getResult() == ButtonType.OK){
getMainTabPane().getTabs().remove(getMainTabPane()
.getSelectionModel()
.getSelectedItem());
}else{
e.consume();
}
}
});
}
#Override
public void initialize(URL location, ResourceBundle resources) {
Platform.runLater(this::loadSubTabPaneAsTabContent);
getMainTabPane().setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
}
}
SubTabPane.java
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.TabPane;
public class SubTabPane {
#FXML private TabPane subTabPane;
TabPane getSubTabPane() { return subTabPane; }
}
mainTabPane.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.MainTabPane">
<children>
<TabPane fx:id="mainTabPane" prefHeight="400.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" />
</children>
</AnchorPane>
subTabPane.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.SubTabPane">
<children>
<TabPane fx:id="subTabPane" layoutX="7.0" prefHeight="400.0" prefWidth="593.0">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
I tried something similar in an application with tabs coresponding to opened projects. The problem apears when the TabDragPolicy is set to REORDER, I smash a tab closing button, a confirmirmation dialog apears asking me if I'd like to save the project, and the event gets consumed if I cancel tab closing. If you remove any of these three (the drag policy, the dialog or event consuming), the tab does not freeze. Removing tab and adding it back to the same position helps, but looks ugly.
The following approach works perfectly for some reason:
tab.setOnCloseRequest(e -> {
tab.getTabPane().setTabDragPolicy(TabPane.TabDragPolicy.FIXED);
// your confirmation code
Platform.runLater(() -> tab.getTabPane().setTabDragPolicy(TabPane.TabDragPolicy.REORDER));
});
Why do you have code to manually remove the tab?
This works for me:
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.Event;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
CheckBox askFirst = new CheckBox("confirm before allowing close");
Tab tab = new Tab("Close Me", askFirst);
tab.setOnCloseRequest((Event t) -> {
if (askFirst.isSelected()) {
Alert areYouSureAlert = new Alert(Alert.AlertType.CONFIRMATION, "Are you sure?", ButtonType.YES, ButtonType.NO);
Optional<ButtonType> result = areYouSureAlert.showAndWait();
if (result.isEmpty() || result.get() != ButtonType.YES) {
t.consume();
}
}
});
TabPane tp = new TabPane(tab);
stage.setScene(new Scene(tp));
stage.show();
Platform.setImplicitExit(true);
}
}
Your problem is in this code:
if(alert.getResult() == ButtonType.OK){
getMainTabPane().getTabs().remove(getMainTabPane()
.getSelectionModel()
.getSelectedItem());
}else{
e.consume();
}
all you really need is:
if (alert.getResult() != ButtonType.OK) {
e.consume();
}
To remove the tab, let the event be pressed, to not close the tab, consume the event. You are likely confusing the TabPane which thinks it is supposed to be removing a tab that you have already tried to remove.
Well, I found the bug in the end. This was happening because I had a TabDragPolicy enabled during initialization. I never thought that this could cause such problem so this is why I didn't mention it. It seems that when I consume() the event, the TabDragPolicy is not applied anymore and this makes the Tab to completely freeze. Once I removed the TabDragPolicy.REORDER from initialize the issue stopped.

Add a custom component in JavaFX

I would like to add a custom element into a VBox.
For example: being able to write VBox.getChildren().add(element) and element is a custom node created by me in FXML.
I already followed this tutorial: https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm
but the example only shows how to do this inside the same controller (a single controller, i already have my "big" controller, which is WinnerController, I would like to split the two classes, one that manages the single element, and one that manages the whole scene Winner.fxml).
I already have a class WinnerController which is the controller of my FXML Winner.fxml.
Here the code of my Winner.fxml:
<AnchorPane id="paneWinner" fx:id="paneWinner" prefHeight="800.0" prefWidth="1280.0" stylesheets="#winner.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.gui.WinnerController">
<children>
<VBox layoutX="434.0" layoutY="125.0" prefHeight="250.0" prefWidth="413.0" spacing="10.0">
<children>
<AnchorPane id="leaderBoardElement" prefHeight="80.0" prefWidth="413.0" stylesheets="#leaderBoard.css">
<children>
<Text layoutX="49.0" layoutY="45.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" wrappingWidth="107.13671875" />
</children></AnchorPane>
</children>
</VBox>
I would like to dynamically add element with the id "leaderBoardElement" (so an AnchorPane + Text) into my VBox.
How can i do that?
Edit: I also tried with this solution:How to understand and use `<fx:root>` , in JavaFX?
but i keep getting nothing. When i do vbox.getChildren().add(new MyComponent());
called in my WinnerControlleri get nothing.
WinnerController class:
public class WinnerController implements Initializable {
#FXML
private VBox leaderBoard;
#FXML
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Winner Init");
MyComponent test = new MyComponent();
System.out.println(test);
// leaderBoard.getChildren().add(new MyComponent());
}
}
My Component class:
public class MyComponent extends AnchorPane {
#FXML
private TextField textField ;
#FXML
private Button button ;
public MyComponent() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyComponent.fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
textField.setText("HELLO!");
} catch (IOException exc) {
// handle exception
System.out.println("ELEMENT NOT CREATE!!!");
}
}
}
Winner.fxml:
<AnchorPane id="paneWinner" fx:id="paneWinner" prefHeight="800.0"
prefWidth="1280.0" stylesheets="#winner.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.gui.WinnerController">
<children>
<VBox fx:id="leaderBoard" layoutX="434.0" layoutY="125.0" prefHeight="250.0" prefWidth="413.0" spacing="10.0" />
MyComponent.fxml:
<fx:root type="javafx.scene.layout.AnchorPane" fx:id="leaderBoardElement" id="leaderBoardElement">
<TextField fx:id="textField" />
<Button fx:id="button" />
And i call the creation and loading of Winner.fxml from another class like this:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/Winner.fxml"));
if (loader!=null)
System.out.println("LOADER NOT NULL!!");
try{
System.out.println("TRY!");
Parent root = (Parent) loader.load();
if(root!=null)
System.out.println("ROOT NOT NULL!!");
Scene startedGame = new Scene(root, 1280, 800, Color.WHITE);
if(startedGame!=null)
System.out.println("SCENE NOT NULL!");
Stage window = (Stage) paneCarta0.getScene().getWindow();
if (window!=null)
System.out.println("WINDOW NOT NULL!!");
window.setScene(startedGame);
window.show();
catch (IOException Exception) {
System.out.println("View not found. Error while loading");
}
The problem is inside the new MyComponent(), where probably i get an exception and it propagates to my main caller. I've tried everything but i can't figure out why it can't create the MyComponent object.
If your custom component is in a separate FXML file you can do this.
In your WinnerController class:
#FXML
private void initialize() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getRessource("customElement.fxml"));
fxmlLoader.setController(new CustomElementController()); //Or just specify the Controller in the FXML file
myVBox.getChildren().add(fxmlLoader.load());
}
Edit: In this solution there should be NO <fx:include> tags in your main fxml

JavaFX Canvas Returning Null

For anyone experienced with JavaFX, I have made a canvas inside my scene builder, but when I actually try to access said canvas it is null, I am not sure why as I know its made inside my scene builder and shows up in my FXML File
Ive gone ahead and pushed the code to github, it can be found here if anyone wants to look and see if I did something wrong:
https://github.com/ProSavage/JavaFXCalculator/tree/master/src/application/grapher
Feel free to give any other advice as well!
Here is the relevant code
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="application.grapher.GrapherController">
<children>
<HBox alignment="CENTER" layoutX="4.0" layoutY="280.0" prefHeight="20.0"
prefWidth="593.0">
<children>
<TextArea prefHeight="37.0" prefWidth="569.0" />
</children>
</HBox>
<Button layoutX="238.0" layoutY="336.0" mnemonicParsing="false"
prefHeight="50.0" prefWidth="125.0" text="Graph" />
<HBox fx:id="canvasBox" layoutX="14.0" layoutY="20.0"
prefHeight="250.0" prefWidth="570.0" />
</children>
</AnchorPane>
The class
public class GrapherController {
#FXML
private HBox canvasBox;
public void test() {
Canvas canvas = new Canvas(570,250);
canvasBox.getChildren().add(canvas);
double startX = canvas.getWidth()/2 * -1;
double endX = startX * -1;
double startY = canvas.getHeight()/2 * -1;
double endY = startY * -1;
GraphicsContext grapher = canvas.getGraphicsContext2D();
grapher.beginPath();
String equation = "x+1";
grapher.moveTo(startX,Evaluator.eval(equation.replace("x",startX + "")));
for (double i = startX; i < endX; i++) {
grapher.lineTo(startX,Evaluator.eval(equation.replace("x",String.valueOf(i))));
}
}
}
Basically when running the test method, If I create a canvas and add it to the box, the canvas is null and if I try making it into the xml file itself its still null. I feel like theres some essential step I am missing to the canvas it self.
It is actually your canvasBox field that is null. But the issue lies in your GrapherScene class. You are manually creating a GrapherController and calling test() on that instance. There is no possible way for canvasBox to not be null in that instance:
You never set it yourself
The instance wasn't created by a FXMLLoader which means no dependency injection of the FXML fields occur
Change:
public GrapherScene() {
try {
Stage grapherStage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("grapher.fxml"));
Scene scene = new Scene(root, 600, 400);
//scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
grapherStage.setScene(scene);
grapherStage.setTitle("Grapher");
grapherStage.show();
} catch (Exception ex) {
ex.printStackTrace();
}
GrapherController grapher = new GrapherController();
grapher.test();
}
To:
public GrapherScene() {
try {
Stage grapherStage = new Stage();
FXMLLoader loader = new FXMLoader(getClass().getResource("grapher.fxml"));
grapherStage.setScene(new Scene(loader.load());
grapherStage.setTitle("Grapher");
grapherStage.show();
// Must be called AFTER loader.load()
// Method has generic return type so explicit casting is not necessary in this case
GrapherController grapher = loader.getController();
grapher.test();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Note: I'm using the instance FXMLLoader.load() method here and not the static FXMLLoader.load(URL) method.
For more information:
Accessing FXML controller class
JavaFX - How to get FXML Controller? [duplicate]
Passing Parameters JavaFX FXML
Introduction to FXML

why Javafx standalone application accepting double click?

Here is my Main java file.The probelm is that the Whole project is working on double click when i launch it.
public Stage primaryStage;
public BorderPane rootLayout;
private Pane splashLayout;
private ProgressBar loadProgress;
private Label progressText;
private static final int SPLASH_WIDTH = 600;
private static final int SPLASH_HEIGHT = 400;
public static void main(String[] args) throws Exception {
launch(args);
}
#Override
public void start(final Stage initStage) throws Exception {
//this.primaryStage = primaryStage;
FXMLLoader fxmlLoader1 = new FXMLLoader(getClass().getResource(
"KDAF_Splash.fxml"));
try {
// flag = false;
Parent root2 = fxmlLoader1.load();
Stage stage2 = new Stage();
stage2.initStyle(StageStyle.TRANSPARENT);
// masterpane = new Pane();
// masterpane.setOpacity(1);
// stage2.setTitle("Create New Project");
stage2.setScene(new Scene(root2, 600, 400));
stage2.show();
PauseTransition delay = new PauseTransition(Duration.seconds(5));
delay.setOnFinished( event ->{ stage2.close();showMainStage();} );
delay.play();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
};
private void showMainStage(
) {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Preloader.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Stage stage=new Stage();
stage.setTitle("Activation");
Scene scene = new Scene(rootLayout);
//stage.initStyle(StageStyle.DECORATED);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
showPersonOverview();
//mainStage.show();
/* mainStage.setTitle("Activation Wizard");
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
// primaryStage.initStyle(StageStyle.UTILITY);
mainStage.setResizable(false);
mainStage.initStyle(StageStyle.UNDECORATED);
mainStage.setScene(scene);
mainStage.show();
showPersonOverview();*/
} catch (IOException e) {
e.printStackTrace();
}
}
public void showPersonOverview() {
try {
// Load person overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("activation wizard.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
personOverview.setPrefHeight(400);
// Set person overview into the center of root layout.
rootLayout.setCenter(personOverview);
} catch (IOException e) {
e.printStackTrace();
}
}
private void showSplash(
final Stage initStage,
Task<?> task,
InitCompletionHandler initCompletionHandler
) {
progressText.textProperty().bind(task.messageProperty());
loadProgress.progressProperty().bind(task.progressProperty());
task.stateProperty().addListener((observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
loadProgress.progressProperty().unbind();
loadProgress.setProgress(1);
initStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.2), splashLayout);
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(actionEvent -> initStage.hide());
fadeSplash.play();
initCompletionHandler.complete();
} // todo add code to gracefully handle other task states.
});
Scene splashScene = new Scene(splashLayout);
initStage.initStyle(StageStyle.UNDECORATED);
final Rectangle2D bounds = Screen.getPrimary().getBounds();
initStage.setScene(splashScene);
initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
initStage.show();
}
public interface InitCompletionHandler {
public void complete();
}
}
The FXml is given below. Please help me to resolve this issue. If the question is not clear help me to explain better. The main problem is when the application is launched after splash screen. The button accepts double click and then moves to load next FXML. this is been very painful as i have to double click everytime instead of single click. I am not able to identify the problem here. Whether it is a problem that persists from scene builder or the problem is in the main preloader class.Even the menu item is accepting double click. I try to google the solution for but could not find any solution. please look int the code and help to resolve this issue. I have done a lot of R&D but all went vain . There might be a little problem in it but i am not being able to identify it. Please ignore the formatting of code and unused variables. The code is not final yet. finally i would like to remind the main problem is that after launching, the application is working only on double click. lets look at the work flow to understand it better. SPLASH SCREEN->ACTIVATION WIZARD-DOUBLE CLICK ON A BUTTON->TIP SCREEN-DOUBLE CLICK ON A BUTTON->PROJECT SCREEN->DOUBLE CLICK TO OPEN ANYTHING. It is really frustrating. please help.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-border-color: black;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="EventHandlingController">
<children>
<Button layoutX="301.0" layoutY="333.0" mnemonicParsing="false" text="Buy Full Version" />
<Button fx:id="myButton7" layoutX="420.0" layoutY="333.0" mnemonicParsing="false" onAction="#Showtip" prefHeight="25.0" prefWidth="114.0" text="Continue Trial " />
<TextField editable="false" layoutX="85.0" layoutY="108.0" prefHeight="151.0" prefWidth="449.0" style="-fx-background-color: silver;" text="You have <xx> days left on your trial.">
<font>
<Font size="21.0" />
</font>
</TextField>
<Label layoutX="85.0" layoutY="23.0" prefHeight="37.0" prefWidth="135.0" text="Activation Wizard">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
<Button fx:id="closebutt" layoutX="573.0" layoutY="2.0" mnemonicParsing="false" onAction="#closebuttonD" prefHeight="15.0" prefWidth="20.0" text="X" />
</children>
</AnchorPane>

Categories