JavaFX window setTitle - javafx

I have a main class which is the following:
public class Window extends Application {
#Override
public void start(Stage foablak) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Foablak.fxml"));
Scene scene = new Scene(root);
foablak.setScene(scene);
foablak.setWidth(900);
foablak.setHeight(700);
foablak.setResizable(false);
foablak.setTitle("Window");
foablak.show();
}
public static void main(String[] args) {
launch(args);
}
}
How can I update the Title of the from another .java class without closing the window and open a new one?

Exposing properties using static, just for the sake of exposing, may be considered as a bad design. You have different ways to achieve the same, for example, expose a method from the Window class which sets the stage title.
public class Window extends Application {
private Stage stage;
#Override
public void start(Stage foablak) throws Exception {
stage = foablak;
Parent root = FXMLLoader.load(getClass().getResource("Foablak.fxml"));
Scene scene = new Scene(root);
foablak.setScene(scene);
foablak.setWidth(900);
foablak.setHeight(700);
foablak.setResizable(false);
foablak.setTitle("Window");
foablak.show();
}
public static void main(String[] args) {
launch(args);
}
public void setStageTitle(String newTitle) {
stage.setTitle(newTitle);
}
}

Yes, you can. Inside of your Application.start() method, save a reference to your primary Stage that you can access elsewhere, and then call Stage.setTitle().
class MyApplication extends Application {
public static Stage primaryStage;
#Override
public void start(Stage primaryStage) {
MyApplication.primaryStage = primaryStage;
// ...
}
}
MyApplication.primaryStage.setTitle("New Title");
As an aside, I would avoid calling your class Window, as that is the name of one of the JavaFX classes.

The following may not be the solution you were looking for, but it might be useful for some of the developers:
Scenario: There is only 1 JavaFX app; The app needs to be run
multiple times; You want to differentiate who is running the app
Attention: Pay attention of the running order of the Main and
Controller class
Solution: i. In the Controller Class, declare a private static variable, e.g., private static String strWho; ii. Expose strWho by providing a getter method. e.g.: public static String getWho(){
return strWho;
}; iii. Implement the initialize method for the Controller, and based on your need, assign a distinct value each time you run the JavaFX app. eg., #FXML
public void initialize() {
strWho = "you need to have logic here, to have a distinct value each time you run the app";
}
In the Main start method, right before you call the stage.show, set the title. eg:
primaryStage.setTitle(Controller.getWho()));
primaryStage.show();
One way to implement the logic for distinct value of the strWho each time you run the app: You can have a TextInputDialog in the Controller's initialize method, to accept user input, by asking for a name etc.

Related

JavaFX - parsing child arguments back to parent

I have 2 Controllers and I want to pass values from second controller to first controller, here are code sample:
FXMLController.java
private int paramAnswers;
private int paramNotificationTime;
private int paramNotificationDelay;
#FXML
private void handleMenuItemOptionsAction(ActionEvent event) throws IOException{
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Options.fxml")); // UNDECORATED*
Scene scene = new Scene(root, Color.TRANSPARENT);
final Stage stage = new Stage();
stage.setTitle("Options");
stage.setScene(scene);
stage.show();
}
public void setOptionsParams(int paramAnswers, int paramNotificationTime, int paramNotificationDelay){
this.paramAnswers = paramAnswers;
this.paramNotificationTime = paramNotificationTime;
this.paramNotificationDelay = paramNotificationDelay;
}
and second controller:
OptionsController.java
private FXMLController parentController;
private int paramAnswers;
private int paramNotificationTime;
private int paramNotificationDelay;
#Override
public void initialize(URL location, ResourceBundle resources) {
.... }
#FXML
private void handleButtonSaveAction(ActionEvent event) throws IOException{
/*Pass these parameteres OptionsController parameters back to the FXMLController like parentController.setOptionsParams(paramAnswers, paramNotificationTime, paramNotificationDelay);
*/
(((Button)event.getSource()).getScene().getWindow())).close();
}
Arleady tried with parsing FXMLControler as .this into OptionsController initialize method, tried making listers and bunch of other resolved problems on stackoverflow but it just don't want work :< I need to pass that atributes back to FXMLController and close child window, so my main app would change behavior depending on passed values... :X
For any help I will be grateful
you can have a function in the second controller let's say passParams() set it's parameters what every you want to pass to that controller and from the first controller when you click on a button or something
this line
FXMLLoader.load(getClass().getResource("/fxml/Options.fxml"));
need to be changed to
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Options.fxml"));
Parent root = (Parent) loader.load();
OptionsController controller = loader.getController();
EDIT
you need to pass the first controller to the second controller
controller.setParentController(this); // this is the first controller
in Second controller
FirstController mController;
public void setParams(FirstController controller) {
this.mController = controller;
}
now in the button click function you use the mController you got from the previous step
mController.setOptionsParams(...); //send the params collected from the textfields
this function is implemented in the FirstController
Note: a more general way to do this by using call-backs it's the same but your code depends on interfaces not concrete classes by implementing a general interface in FirstController that have the setOptionParams() method
First you add a callback interface to your parent controller class:
public interface OptionCallback {
public void setOptionsParams(int paramAnswers, int paramNotificationTime, int paramNotificationDelay);
}
public class YourParentController implements Initializable, OptionCallback {
...
}
Using the FXMLLoader object you can get a hold of your child controller object and pass the parent object to it:
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource("yourFXML.fxml"));
Parent root = (Parent) loader.load();
YourChildController yourChildController = loader.<YourChildController>getController();
yourChildConrtoller.registerCallback(this);
In the childController you save that callback:
private OptionCallback optionCallback;
public void registerCallback(OptionCallback callback) {
optionCallback = callback;
}
And whenever results are ready you use it to pass it to parent:
optionCallback.setOptionsParams(...);

How can i create a stage in java FX which forces user to first close it for doing anything else?

I am creating a desktop app using java fx and here I want to prevent the user from accessing the PC unless my app is closed.
I tried using showAndWait() function but it is not applicable to primary stage.
Its a single page app.
Help will be appreciated. Thanks!
Here is my main class and i am using scene builder for designing.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
TilePane root = FXMLLoader.load(getClass().getResource("/application/Layout.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.showAndWait();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}

Javafx run another class using hyperlink [duplicate]

I've been smashing my head with JavaFx...
This works for when there's no instances of an application running:
public class Runner {
public static void main(String[] args) {
anotherApp app = new anotherApp();
new Thread(app).start();
}
}
public class anotherApp extends Application implements Runnable {
#Override
public void start(Stage stage) {
}
#Override
public void run(){
launch();
}
}
But if I do new Thread(app).start() within another application I get an exception stating that I can't do two launches.
Also my method is called by an observer on the other application like this:
#Override
public void update(Observable o, Object arg) {
// new anotherApp().start(new Stage());
/* Not on FX application thread; exception */
// new Thread(new anotherApp()).start();
/* java.lang.IllegalStateException: Application launch must not be called more than once */
}
It's within a JavaFX class such as this:
public class Runner extends Applications implements Observer {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage){
//...code...//
}
//...methods..//
//...methods..//
#Override
public void update(Observable o, Object arg) {
//the code posted above//
}
}
I tried using ObjectProperties with listeners but it didn't work. I need to get this new stage running from within the update method from java.util.observer in some way.
Any suggestions are welcomed. Thanks.
Application is not just a window -- it's a Process. Thus only one Application#launch() is allowed per VM.
If you want to have a new window -- create a Stage.
If you really want to reuse anotherApp class, just wrap it in Platform.runLater()
#Override
public void update(Observable o, Object arg) {
Platform.runLater(new Runnable() {
public void run() {
new anotherApp().start(new Stage());
}
});
}
I did a constructor of another JFX class in Main class AnotherClass ac = new AnotherClass(); and then called the method ac.start(new Stage);. it worked me fine. U can put it either in main() or in another method. It does probably the same thing the launch(args) method does
Wanted to provide a second answer because of one caveat of using Application.start(Stage stage).
The start method is called after the init method has returned
If your JavaFX application has Override Application.init() then that code is never executed. Neither is any code you have in the second application main method.
Another way to start a second JavaFX application is by using the ProcessBuilder API to start a new process.
final String javaHome = System.getProperty("java.home");
final String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
final String classpath = System.getProperty("java.class.path");
final Class<TestApplication2> klass = TestApplication2.class;
final String className = klass.getCanonicalName();
final ProcessBuilder builder = new ProcessBuilder(javaBin, "-cp", classpath, className);
final Button button = new Button("Launch");
button.setOnAction(event -> {
try {
Process process = builder.start();
} catch (IOException e) {
e.printStackTrace();
}
});

Run method from controller class on startup Javafx

I got a javafx application and I got a main where I set up my stage and launch the application. I also have a controller class:
public class Controller
{
#FXML Button button;
public void test(){
button.setText("Button");
}
}
How would I go about running the test method on startup. I know I can create an instance in the main class...
public class Main extends Application{
public void start(Stage primaryStage) throws Exception {
...
public static void main (String[] args){
launch (Main.class);
Controller cont = Controller();
cont.test();
}
}
and that would work. However it is not ideal for me. I was wondering if it was possible to run the method directly from the controller class, if not is there a better way of handling this? Thanks
The initialize() method is called automatically when the FXML is loaded:
public class Controller
{
#FXML Button button;
public void initialize(){
button.setText("Button");
}
}
Note that your code in the Main class won't work at all. First, launch() does not exit until you exit the application, and second, you are calling it on a new instance of the controller, not the one that is connected to the UI you load from the FXML file.

How to update text box in JavaFX Application after 5 seconds of running?

I have a single controller class "FXController.java" and my FXApplication.java that extends "Application" and contains the launch code. In a separate class "TestFX.java" I call the start method in the "FXApplication.java" that starts the gui. I want to be able to access its controller so that I can change the text within a textfield of the controller. In my FXApplication.java, within the "launch" method I create a variable for the FXLoader and use the "getController" method and set it to a public variable: public FXController theController.
Within the TestFX.java, after I call the "start" method in the main method that launches FXApplication.java in a new runnable, I try to access the controller to change the contents of a single textfield, I get an exception that says controller is null. What is the proper way for me to change the contents of the textfield? I feel that the threading is causing problems.
What I am trying to do in my main method is:
Launch the JavaFX Application/GUI
5 seconds later (sleep), change the text of the text field in FXController.java to "Hello World".
Note that the fxml file loaded/used by FXApplication.java is pointed correctly to the FXController.java. Am wondering if there is some way to access the controller despite having spawned a new runnable for the FX application.
FXApplication.java
public class FXApplication extends Application {
public FXController theController;
public void start() {
Application.launch(FXApplication.class, args);
}
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmll = new FXMLLoader(getClass().getResource("fxml_example.fxml"));
Parent root = fxmll.load();
theController = fxmll.getController();
stage.setTitle("FXML Welcome");
stage.setScene(new Scene(root, 300, 275));
stage.show();
}
}
My TestFX.java
public class TestFX {
public static FXApplication fxApp = new FXApplication();
public ExecutorService execs;
public Future<?> fut;
TestFX(ExecutorService execs) {
this.execs = execs;
}
public void start() {
fut = execs.submit(new Runnable() {
#Override
public void run() {
fxApp.start();
}
});
}
public static void main(String[] args) {
ExecutorService execs = Executors.newCachedThreadPool();
TestFX testFx = new TestFX(execs);
testFx.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//fxApp.theController.setTextBoxText("Hello Word");
Platform.runLater(() -> fxApp.theController.setTextBoxText("Hello Word"));
}
Stuff that you want to do like this, you should use the Task class. This does all the heavy lifting for you and all you have to do is set up the code you want to run the FXAT when the task completes. Here's an example, I've left out the controller stuff, because it just clutters up the concepts:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
private static Label label;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
label = new Label();
label.setText("Waiting...");
StackPane root = new StackPane();
root.getChildren().add(label);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
return null;
}
};
sleeper.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
label.setText("Hello World");
}
});
new Thread(sleeper).start();
}
}
The "sleeper" Task doesn't do anything except sleep, but it's going to sleep on a new thread so the FXAT can keep on responding to screen activity. Then when the sleep finishes, the event handler for the succeed will run on the thread that instantiated the Task, in this case the FXAT.
Your code has two problems.
First, you are calling the static FXMLLoader.load(URL) method, instead of calling load on your FXMLLoader instance. Consequently, the FXMLLoader instance never gets to initialize its controller. You need
FXMLLoader fxmll = new FXMLLoader(getClass().getResource("fxml_example.fxml"));
Parent root = fxmll.load();
The second issue is that you are then changing the text of the text box from a background thread, instead of from the FX Application Thread. (Unless you're handling this in the controller class: you don't show the code for that.) You need
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Platform.runLater(() -> fxApp.theController.setTextBoxText("Hello Word"));
You can also do this with a PauseTransition:
PauseTransition pause = new PauseTransition(Duration.seconds(5));
pause.setOnFinished(event -> fxApp.theController.setTextBoxText("Hello Word"));
pause.play();

Resources