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

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();
}

Related

Problem with Controller and FXML, Grid Pane is Null

I have a problem with fxml controller communication.
I have App class which is a controller:
package org.example.gui;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import org.example.Game;
import org.example.Main;
import java.io.IOException;
public class App extends Application {
private Game game;
private MapVisualiser mapV;
#FXML
private GridPane mapGridPane;
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/main-scene.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 1530, 790);
stage.setResizable(true);
stage.setMaximized(true);
stage.setTitle("GymSnake");
stage.setScene(scene);
this.game = new Game();
this.mapV = new MapVisualiser(game.getMap(),mapGridPane);
stage.show();
}
}
and a fxml file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.GridPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.gui.App">
<GridPane fx:id="mapGridPane" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" nodeOrientation="LEFT_TO_RIGHT">
</GridPane>
</AnchorPane>
Also the MapVisualiser code to make sure everything is working fine
public MapVisualiser(Map map, GridPane gridPane) {
this.map = map;
this.gridPane = gridPane;
calculateColumnsAndRowsSize();
}
private void calculateColumnsAndRowsSize() {
int squareHeight = (int) Math.ceil(1.0 * Configuration.GRID_HEIGHT / map.getN());
int squareWidth = (int) Math.ceil(1.0 * Configuration.GRID_WIDTH / map.getN());
this.sideLengthOfSquarePx = Math.max(40, Math.max(squareWidth, squareHeight));
gridPane.getColumnConstraints().add(new ColumnConstraints(sideLengthOfSquarePx));
gridPane.getRowConstraints().add(new RowConstraints(sideLengthOfSquarePx));
}
I don't understand why my grid pane returns null
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.layout.GridPane.getColumnConstraints()" because "this.gridPane" is null
Please help

NullPointerException Setting ComboBox From FXML [duplicate]

I'm really struggling to understand JavaFX controllers, my aim is to write to a TextArea to act as a log.
My code is below, but I want to be able to change values ETC from another class that I can call when needed. I have tried to create a controller class that extents Initializable but i cant get it to work. Could some one steer me in the correct direction?
I want to move the #FXML code at the bottom to another class and it update the Scene.
package application;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
Scene scene = new Scene(root,504,325);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
public Thread thread = new Thread(new webimporter());
#FXML
public Label runningLabel;
#FXML
public TextArea txtArea;
#FXML
void runClick(ActionEvent event) throws IOException{
changeLabelValue("Importer running...");
thread.start();
}
#FXML
protected void stopClick(ActionEvent event){
changeLabelValue("Importer stopped...");
thread.interrupt();
}
#FXML
void changeLabelValue(String newText){
runningLabel.setText(newText);
}
void changeTextAreaValue(String newText1){
txtArea.setText(newText1);
}
}
Don't make the Application class a controller. It's a sin. There are other questions and answers which address this, but my search skills cannot find them at this time.
The reason it is a sin is:
You are only supposed to have one Application instance, and, by default, the loader will make a new instance, so you end up with two application objects.
Referencing the member objects is confusing, because the original launched application doesn't have the #FXML injected fields, but the loader created application instance does have #FXML inject fields.
Also, unrelated advice: Don't start trying to write multi-threaded code until you have the application at least working to the extent where it displays your UI.
A multi-threaded logger for JavaFX is in the answer to Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks, though unfortunately it is not straight-forward in its implementation and comes with little documentation.
textlogger/Root.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textlogger.ImportController">
<children>
<HBox alignment="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0">
<children>
<Button mnemonicParsing="false" onAction="#run" text="Run" />
<Button mnemonicParsing="false" onAction="#stop" text="Stop" />
<Label fx:id="runningLabel" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
textlogger.ImportController.java
package textlogger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
public class ImportController {
#FXML
private Label runningLabel;
#FXML
private TextArea textArea;
private WebImporter importer;
#FXML
void run(ActionEvent event) throws IOException {
changeLabelValue("Importer running...");
if (importer == null) {
importer = new WebImporter(textArea);
Thread thread = new Thread(
importer
);
thread.setDaemon(true);
thread.start();
}
}
#FXML
void stop(ActionEvent event){
changeLabelValue("Importer stopped...");
if (importer != null) {
importer.cancel();
importer = null;
}
}
private void changeLabelValue(String newText){
runningLabel.setText(newText);
}
}
textlogger.WebImporter.java
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.TextArea;
import java.time.LocalTime;
public class WebImporter extends Task<Void> {
private final TextArea textArea;
public WebImporter(TextArea textArea) {
this.textArea = textArea;
}
#Override
protected Void call() throws Exception {
try {
while (!isCancelled()) {
Thread.sleep(500);
Platform.runLater(
() -> textArea.setText(
textArea.getText() + LocalTime.now() + "\n"
)
);
}
} catch (InterruptedException e) {
Thread.interrupted();
}
return null;
}
}
textlogger.TextLoggingSample.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextLoggingSample extends Application {
#Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(
getClass().getResourceAsStream(
"Root.fxml"
)
);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

JAVAFX + SCENE BUILDER 8.3.0 problems with KeyEvent (this mysterious)

I really don't understand KeyEvent.
sometime work, sometime not.
in my first videogame(i try to make some simple game only for fun and improve my skill) work, i make all keybind to one unique method because if i do a second method(Keyevent) it doesn't nothing.
Today i make a little fun program with a my wife head that run on the screen randomly
and..when i doing the first KeyEvent it do nothing, like a dead method.
then i decided to find the cause at all cost. copy and paste the working KeyEvent method of previous program (position, root,name,nodes) and nothing to do. sometime work sometime not.
when i do new project same result. sometime work sometime not.
i dont think if i post some pictures it serves something.
any tips? and sorry for my english.
WINDOWS 8 JAVAFX SCENEBUILDER ECLIPSE
the method is like this : (obviously i write the name of the method in scenebuilder)
public void Press(KeyEvent event) {
if(event.getCode()==KeyCode.ENTER) {action14();}
else {\\ do something }event.consume();
}
event.consume(); was only a try
HERE the code:
MAIN
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.input.KeyCode;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("prova1.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
scene.getRoot().requestFocus();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane focusTraversable="true" prefHeight="344.0" prefWidth="384.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.Mycontroller">
<children>
<ImageView fitHeight="1080.0" fitWidth="1980.0" focusTraversable="true" layoutX="-39.0" layoutY="-23.0">
<image>
<Image url="#grass123.jpg" />
</image>
</ImageView>
<ImageView fx:id="war" focusTraversable="true" layoutX="244.0" layoutY="96.0" onKeyPressed="#Press123">
<image>
<Image url="#giphy-tumblr.gif" />
</image>
</ImageView>
<ImageView fx:id="alla" fitHeight="102.0" fitWidth="105.0" focusTraversable="true" layoutX="545.0" layoutY="574.0" onMouseClicked="#allaclic" pickOnBounds="true">
<image>
<Image url="#faccino.png" />
</image>
</ImageView>
<ImageView fx:id="base" fitHeight="20.0" fitWidth="8000.0" layoutX="-671.0" layoutY="666.0">
<image>
<Image url="#../../../../Desktop/barra.png" />
</image>
</ImageView>
</children>
</AnchorPane>
CONTROLLER
import java.net.URL;
import java.util.ResourceBundle;
import javafx.animation.Animation;
import javafx.animation.AnimationTimer;
import javafx.animation.FadeTransition;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.RotateTransition;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
public class Mycontroller<I> implements Initializable{
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void Press123(KeyEvent y) {
if(y.getCode()==KeyCode.ENTER) {war.relocate (50,50); }
else {}
}
#FXML
public ImageView alla;
#FXML
public ImageView war;
#FXML Circle cir=new Circle(40,40,40);
public int random() {
int a=0;a=(int) (Math.random()*300-300);
return a;}
public void allaclic(MouseEvent o) {
AnimationTimer time=new AnimationTimer() {
#Override
public void handle(long now) {
int x=0;x+=1;int y=0;y+=1;
saluto(x,y);
}
};time.start();
TranslateTransition tra=new TranslateTransition();
tra.setNode(alla);
tra.setToX(random());
tra.setToY(random());
tra.setCycleCount(1);
tra.setAutoReverse(true);
tra.setDuration(Duration.seconds(1.5));
tra.setOnFinished(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent t) {allaclic(o);}
});
tra.play();o.consume();
FadeTransition trans = new FadeTransition(Duration.seconds(1), (alla
));
trans.setFromValue(1.0);
trans.setToValue(.00);
trans.setCycleCount(FadeTransition.INDEFINITE);
trans.setAutoReverse(true);
trans.setOnFinished(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent t) {t.consume();}
});
trans.play();
}
public void rotation() {
RotateTransition rotate=new RotateTransition();
rotate.setNode(alla);
rotate.setByAngle(random());rotate.setFromAngle(random());
rotate.setCycleCount(Animation.INDEFINITE);
rotate.setAutoReverse(true);
rotate.play();
int g=0;int y=0;saluto(g,y);
}
public void saluto(int x,int y) {
if(alla.getBoundsInParent().intersects(163,160,15 ,75)) { //something;
}
}
//something}
public void tempohey() {
Timeline time=new Timeline();
time.setAutoReverse(false);
time.setCycleCount(1);
KeyValue kv=new KeyValue(war.layoutXProperty(),200);
KeyFrame kf=new KeyFrame(Duration.millis(1500),kv);
time.getKeyFrames().add(kf);time.play();
}
}
This is more like mcve, and demonstrates a working key-event handler:
public class DrawImage extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("DrawImage.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
scene.getRoot().requestFocus();//key event needs focus
}
public static void main(String[] args) {
launch(args);
}
}
note the important comment about focus
CONTROLLER
public class DrawImageController{
#FXML ImageView war;
#FXML
public void press123(KeyEvent event){
System.out.println("Key Pressed"); // print a message
if(event.getCode()==KeyCode.ENTER) {war.relocate (50,50); }
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="100.0" prefWidth="100.0"
onKeyPressed="#press123"
xmlns="http://javafx.com/javafx/8.0.111"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="stackoverflow.DrawImageController">
<children>
<ImageView fx:id="war" fitHeight="50.0" fitWidth="50.0"
layoutX="50.0" layoutY="20.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="http://icons.iconarchive.com/icons/iconka/meow-2/64/cat-rascal-icon.png" />
</image>
</ImageView>
</children>
</AnchorPane>
to make it mcve make images or any other resources available

Are controller nodes always null inside setOnCloseRequest? [duplicate]

I'm really struggling to understand JavaFX controllers, my aim is to write to a TextArea to act as a log.
My code is below, but I want to be able to change values ETC from another class that I can call when needed. I have tried to create a controller class that extents Initializable but i cant get it to work. Could some one steer me in the correct direction?
I want to move the #FXML code at the bottom to another class and it update the Scene.
package application;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
Scene scene = new Scene(root,504,325);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
public Thread thread = new Thread(new webimporter());
#FXML
public Label runningLabel;
#FXML
public TextArea txtArea;
#FXML
void runClick(ActionEvent event) throws IOException{
changeLabelValue("Importer running...");
thread.start();
}
#FXML
protected void stopClick(ActionEvent event){
changeLabelValue("Importer stopped...");
thread.interrupt();
}
#FXML
void changeLabelValue(String newText){
runningLabel.setText(newText);
}
void changeTextAreaValue(String newText1){
txtArea.setText(newText1);
}
}
Don't make the Application class a controller. It's a sin. There are other questions and answers which address this, but my search skills cannot find them at this time.
The reason it is a sin is:
You are only supposed to have one Application instance, and, by default, the loader will make a new instance, so you end up with two application objects.
Referencing the member objects is confusing, because the original launched application doesn't have the #FXML injected fields, but the loader created application instance does have #FXML inject fields.
Also, unrelated advice: Don't start trying to write multi-threaded code until you have the application at least working to the extent where it displays your UI.
A multi-threaded logger for JavaFX is in the answer to Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks, though unfortunately it is not straight-forward in its implementation and comes with little documentation.
textlogger/Root.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textlogger.ImportController">
<children>
<HBox alignment="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0">
<children>
<Button mnemonicParsing="false" onAction="#run" text="Run" />
<Button mnemonicParsing="false" onAction="#stop" text="Stop" />
<Label fx:id="runningLabel" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
textlogger.ImportController.java
package textlogger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
public class ImportController {
#FXML
private Label runningLabel;
#FXML
private TextArea textArea;
private WebImporter importer;
#FXML
void run(ActionEvent event) throws IOException {
changeLabelValue("Importer running...");
if (importer == null) {
importer = new WebImporter(textArea);
Thread thread = new Thread(
importer
);
thread.setDaemon(true);
thread.start();
}
}
#FXML
void stop(ActionEvent event){
changeLabelValue("Importer stopped...");
if (importer != null) {
importer.cancel();
importer = null;
}
}
private void changeLabelValue(String newText){
runningLabel.setText(newText);
}
}
textlogger.WebImporter.java
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.TextArea;
import java.time.LocalTime;
public class WebImporter extends Task<Void> {
private final TextArea textArea;
public WebImporter(TextArea textArea) {
this.textArea = textArea;
}
#Override
protected Void call() throws Exception {
try {
while (!isCancelled()) {
Thread.sleep(500);
Platform.runLater(
() -> textArea.setText(
textArea.getText() + LocalTime.now() + "\n"
)
);
}
} catch (InterruptedException e) {
Thread.interrupted();
}
return null;
}
}
textlogger.TextLoggingSample.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextLoggingSample extends Application {
#Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(
getClass().getResourceAsStream(
"Root.fxml"
)
);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Window to window interactivity

I have one main screen with a label firstLabel. There is a button openSecondWindow.
Pressing that button opens up a new window, while leaving the first one on the screen.
How would I lock the first screen so that the user cannot interact with it until the second window is closed?
The second window will have a TextField and Button setFirstLabel. When the user enters text in the text field and hits the button, the text from the first window is changed.
How am I supposed to access the controller class for the first window from the second window's controller?
How do I ensure that only one instance of each window be opened at a time? (No duplicates)
i made a small example for you.
If you click on Stage 1 on the Button to open the second Stage, the Button will be disabled, so you cant open one more Stage.
If you type some text into the TextField on Stage2 and click on the Update Button there, the TextField on Stage 1 will be updated and the second Stage will be closed.
Here is the code:
firstWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="de.professional_webworkx.jfx.twowindows.controller.FirstController">
<children>
<TextField fx:id="textField" layoutX="50.0" layoutY="189.0" prefWidth="500.0" promptText="Waiting for input from second Stage..." />
<Button fx:id="openBtn" layoutX="441.0" layoutY="304.0" mnemonicParsing="false" text="open 2 Stage" />
</children>
</AnchorPane>
Second fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" fx:id="mainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="de.professional_webworkx.jfx.twowindows.controller.SecondController">
<children>
<TextField fx:id="textField" layoutX="50.0" layoutY="66.0" prefWidth="243.0" promptText="Type some text" />
<Button fx:id="updateBtn" layoutX="50.0" layoutY="118.0" mnemonicParsing="false" text="update Text on Stage 1" />
</children>
</AnchorPane>
FirstController
package de.professional_webworkx.jfx.twowindows.controller;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
* #version 1.0
*/
public class FirstController implements Initializable {
#FXML
Button openBtn;
#FXML
TextField textField;
private boolean secondOpen;
private Stage secondStage;
FirstController firstController;
public FirstController() {
}
#Override
public void initialize(URL url, ResourceBundle rb) {
this.firstController = this;
System.out.println(firstController);
openBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if(!secondOpen) {
openBtn.setDisable(true);
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Parent load = loader.load();
SecondController controller = (SecondController) loader.getController();
controller.setFirstController(firstController);
Scene scene = new Scene(load);
secondStage = new Stage();
secondStage.setScene(scene);
secondStage.show();
secondOpen = true;
} catch (IOException ex) {
Logger.getLogger(FirstController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}
public void updateText(final String text) {
this.textField.setText(text);
}
public void secondClosed() {
this.secondOpen = false;
this.openBtn.setDisable(false);
secondStage.close();
}
}
SecondController
package de.professional_webworkx.jfx.twowindows.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
* #version 1.0
*/
public class SecondController implements Initializable {
#FXML
AnchorPane mainPane;
#FXML
TextField textField;
#FXML
Button updateBtn;
private FirstController firstController;
#Override
public void initialize(URL url, ResourceBundle rb) {
updateBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
String text = textField.getText();
firstController.updateText(text);
firstController.secondClosed();
}
});
}
public void setFirstController(final FirstController firstController) {
this.firstController = firstController;
}
}
And start it
package de.professional_webworkx.jfx.twowindows;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
*/
public class TwoStages extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent load = FXMLLoader.load(getClass().getResource("firstWindow.fxml"));
Scene scene = new Scene(load);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException ex) {
Logger.getLogger(TwoStages.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The Magic is, to hand over a FirstController object to the SecondController, that you are able to update the TextField on the first Stage.
Hope this will help.
Patrick

Categories