JavaFX - How to change scene using a scene from another class? - java

I have the following class which has a button.
public class GUI extends Application {
private BorderPane mainLayout = new BorderPane();
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Main Menu");
FlowPane layout = new FlowPane();
Button button = new Button("Click");
layout.getChildren().addAll(button);
mainLayout.setTop(layout);
Scene scene = new Scene(mainLayout, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
If I have another class with a scene, how can I update the GUI class to show the scene by pressing the button?

The preferred mechanism would probably be to get the stage dynamically from a trigger event, for example:
button.setOnAction(event -> {
Scene newScene = // ... commands which define the new scene.
Stage stage = ((Node) event.getTarget()).getScene().getStage();
// or alternatively, just:
// Stage stage = button.getScene().getStage();
stage.setScene(newScene);
});
An alternative is to provide a static accessor to the main stage in the Application.
Change your GUI class to add an accessor for the stage:
public class GUI extends Application {
private static Stage guiStage;
public static Stage getStage() {
return guiStage;
}
#Override
public void start(Stage primaryStage) {
guiStage = primaryStage;
// other app initialization logic . . .
}
}
In your class which needs to change the scene for the GUI stage to a new scene, invoke:
Scene newScene = // ... commands which define the new scene.
GUI.getStage().setScene(newScene);
Using a static accessor in this specific instance is generally OK, because you can only have a single Application instance launched for a given JVM execution. The only real drawback is that you have a coded dependency between the class creating your new scene and your Application class. But, for some application types, this won't matter.

Related

JavaFX : Getting back to main page without FXML

I am learning JavaFx on my own and have not reached FXML yet. I am stuck at one application where I plan to have it go back to the main scene of the Application after the user enters their credentials on a second scene. I managed to bring up the second scene from the main one but I could not get from the second scene to the main one. I tried getting the main scene and pane using a getter but no luck. Can you guys teach the right way?
Thank you in advance.
public class Landing extends Application {
BorderPane bp;
Scene scene;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Welcome to our Telco!");
bp = new BorderPane();
VBox vbox = new VBox();
Button login = new Button("Login");
login.setMinWidth(100);
Button acc = new Button("Account Information");
acc.setMinWidth(100);
vbox.getChildren().addAll(acc);
bp.setCenter(vbox);
acc.setOnAction(e ->{
AccountInfo account = new AccountInfo();
primaryStage.setTitle("Account Information"); // Set the stage title
primaryStage.getScene().setRoot(account.getbp());; // Place the scene in the stage
});
scene = new Scene(bp, 750, 550);
primaryStage.setScene(scene);
primaryStage.show();
}
public Pane getbp() {
return bp;
}
public Scene getSc(){
return scene;
}
the button to get the main scene
public class AccountInfo {
BorderPane pane;
Landing main = new Landing();
Scene scene;
AccountInfo() {
Button c = (new Button("Back"));
c.setStyle("-fx-background-color: pink");
c.setOnAction((ActionEvent e) -> {
main.getbp();
main.getSc();
});
public Pane getbp() {
return pane;
}
}
Landing is not a scene, it is an Application. So far from what you've shown, there is only one scene in your whole application. You must never try to instantiate (and subsequently run) more than one instance of any Application class within the same JavaFX application lifetime. You are dangerously going towards this direction when you do Landing main = new Landing(); in your AccountInfo class.
From Javadoc for Application.launch:
Throws: IllegalStateException - if this method is called more than
once.
What you need is to have the first scene for login (i.e. enter credentials). When login is successful, you create a new scene object and populate that scene with your next "view", then set that new scene to the stage.
public class Landing extends Application {
BorderPane bp;
Scene scene;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Welcome to our Telco!");
bp = new BorderPane();
VBox vbox = new VBox();
Button login = new Button("Login");
login.setMinWidth(100);
Button acc = new Button("Account Information");
acc.setMinWidth(100);
vbox.getChildren().addAll(acc);
bp.setCenter(vbox);
acc.setOnAction(e -> {
primaryStage.setTitle("Account Information"); // Set the stage title
BorderPane infoScenePane = new BorderPane();
Scene infoScene = new Scene(infoScenePane);
primaryStage.setScene(infoScene);
});
scene = new Scene(bp, 750, 550);
primaryStage.setScene(scene);
primaryStage.show();
}
}

Can you write two different Java FX scenes as two separate classes?

I'm a beginning Java programmer, finishing up the "Java 101" class at my local university. I'm also pushing myself to learn some extra topics on the side, including Java FX. I've worked through the Java FX tutorials on Oracle's website, plus sat through some YouTube videos, plus read "Java FX for Dummies" (which was the best book I could find for a beginner.) All of this material has taught me a lot of the basics, but some stuff that (should be) relatively simple escapes me.
For example: Let's say I have a Java FX program that uses multiple scenes on one stage. When the user clicks a "Switch!" button, the second scene is swapped out for the first. Easy. I can do all of this in one .java file, no problem. (See code below)
But my .java class file is getting really long and cumbersome to troubleshoot. It would be great if I could define/declare/initialize one scene as one class in one .java file and the second scene as another class in another .java file. This would make keeping track of the components of each scene much, much easier. The problem is, I can't figure out how to do this.
I'd imagine that you would write a Scene1.java class and then a Scene2.java class, and simply pass the stage object between the two when you want to switch scenes. But I can't find an example of how this is done, and all my attempts result in compiler errors or really scary runtime errors.
Does anyone know how this can be done? If so, what would I have to do to modify the SwitchScenes2() method below to create the new Scene2 object and pass it the stage?
Thanks! RAO
/*
JavaFXExample.java
*/
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.event.*;
import javafx.geometry.*;
public class JavaFXExample extends Application{
public static void main(String[] args){
launch(args);
}
Button btnSw1;
Button btnSw2;
Button btnClose;
HBox hbox1;
VBox vbox1;
Scene scene1;
Scene scene2;
Stage stage;
#Override public void start(Stage primaryStage){
btnSw1 = new Button("Switch Scenes!");
btnSw1.setOnAction(
e -> SwitchScenes2() );
btnSw2 = new Button("Switch back!");
btnSw2.setOnAction(
e -> SwitchScenes1() );
btnClose = new Button();
btnClose.setText("Close me!");
btnClose.setOnAction(e -> CloseWindowClick());
hbox1 = new HBox(10);
hbox1.getChildren().addAll(btnSw1);
vbox1 = new VBox(10);
vbox1.getChildren().addAll(btnSw2, btnClose);
scene1 = new Scene(hbox1, 300, 300);
scene2 = new Scene(vbox1, 200, 400);
stage = primaryStage;
stage.setScene(scene1);
stage.setTitle("Example App");
stage.show();
}
public void SwitchScenes1(){
stage.setScene(scene1);
}
public void SwitchScenes2(){
stage.setScene(scene2);
}
public void CloseWindowClick(){
stage.close();
}
}
Pete as I understand you wish to separate one big java file into small files,create Java classes in each class create method(function) that will return layout(HBox,VBox, Flowpane or ....)then in your main create an object of that Java class and use those methods to build on big application.
in my sample I made one main and one separated class with one function,just to show you how its works. In my main there is 2 lables, 2 buttons one layout and one object of the separated class, by clicking the buttons scenes will change
My Main:
public class SwitchSceneSample extends Application {
public static void main(String[] args) {
launch(args);
}
Stage window;
Scene scene1, scene2;
#Override
public void start(Stage primaryStage) throws Exception {
// I am using window as primaryStage
window = primaryStage;
// Label 1
Label label1 = new Label("Welcome to the first scene!");
// Label 2
Label label2 = new Label("This is second scene!");
// Button 1, by pressing this button primaryStage will be set as scene 2
Button button1 = new Button("Go to scene 2");
button1.setOnAction(e -> window.setScene(scene2));
// Button 2, by pressing this button primaryStage will be set as scene 1
Button button2 = new Button("Click to go scene 1");
button2.setOnAction(e -> window.setScene(scene1));
// Creating an object of the class'LayoutOne.java'
LayoutOne l1 = new LayoutOne();
// set my scene 1(by calling method called 'sceneView1()' from class 'LayoutOne.java')
scene1 = new Scene(l1.sceneView1(label1, button1), 200, 200);
// Set my scene 2 inside my main class
StackPane layout2 = new StackPane();
layout2.getChildren().addAll(label2, button2);
scene2 = new Scene(layout2, 600, 300);
// Making my
window.setScene(scene1);
window.setTitle("Scene Switch Sample");
window.show();
}
}
My Second Class:
public class LayoutOne {
public VBox sceneView1(Label label, Button button) {
// Layout 1 - children are laid out in vertical column
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(label, button);
return layout1;
}
}
What you will want to do is create separate classes that both have functions to return the scene. From there you will want to initialize these classes and with a button call a function that will add data to these scene or create a new blank scene (as a quick way to "delete" the scene). But if you want a more professional way to switch between scenes like this you will want to check out the TabPane().
Scene1 scene1 = new Scene1();
Scene2 scene2 = new Scene2();
TabPane tabPane = new TabPane();
Tab tab1 = new Tab();
tab1.setContent(scene1);
tabPane.getTabs().add(tab1);
Tab tab2 = new Tab();
tab2.setContent(scene2);
tabPane.getTabs().add(tab2);
Create a Manager class that contain the main method & initialize the first screen. eg.
public class VMCSManager extends Application {
private Parent content;
private static VMCSManager instance;
public VMCSManager() {
instance=this;
}
public static void main(String[] args) {
launch(args);
}
public static VMCSManager getInstance() {
return instance;
}
#Override
public void start(Stage primaryStage) throws Exception {
initializePanel();
Scene scene = new Scene(content);
stageStyle(primaryStage);
primaryStage.setScene(scene);
primaryStage.show();
}
private void initializePanel() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("fxml/SimulatorDisplay.fxml"));
content = loader.load();
}
public void openCustomerPanel() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("fxml/CustomerDisplay.fxml"));
content = loader.load();
Scene scene = new Scene(content);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Create main controller class for the first screen. eg;
public class SimulatorController implements Initializable{
#FXML
public void clickCustomer (ActionEvent event) throws IOException{
log.info("Starting Customer Panel");
VMCSManager.getInstance().openCustomerPanel();
}
#FXML
public void clickMaintainer(ActionEvent event) throws IOException{
log.info("Starting Maintainer Panel");
VMCSManager.getInstance().openMaintainerPanel();
}
}
Lastly Create the controller class for the specified screen. eg`
public class CustomerController extends SimulatorController{
#FXML
private Label brand1Lbl;
#FXML
private Label brand2Lbl;
#FXML
private Label brand3Lbl;
#FXML
private Label brand4Lbl;
#FXML
private Label brand5Lbl;
#FXML
private Label statusLbl1;
#FXML
private Label statusLbl2;
private static final Logger log=LoggerFactory.getLogger(CustomerController.class);
public CustomerController() {
context= new BuyingStateContext();
}
public void initialize(URL location, ResourceBundle resources) {
this.location = location;
this.rb = resources;
coinsValidityFlash.setVisible(false);
insertCoinTxt.setDisable(true);
brand1Btn.setStyle("-fx-background-color: #CACACA;");
brand2Btn.setStyle("-fx-background-color: #CACACA;");
brand3Btn.setStyle("-fx-background-color: #CACACA;");
brand4Btn.setStyle("-fx-background-color: #CACACA;");
brand5Btn.setStyle("-fx-background-color: #CACACA;");
populateVending();
}
.
.
.
}
`

How could i disable primary stage when a new stage popup

I have button that will popup new stage but primary stage wont disable it still can be click so how to disable the primary stage.
This is my code for stage and scene
private static final Stage stage = new Stage();
private static final Stage newstage = new Stage();
/**
*
*/
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().addAll(this.getClass().getResource("background.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
public void chgScene (String str) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource(str));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public void addStage (String str) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource(str));
Scene scene = new Scene(root);
newstage.setScene(scene);
newstage.setResizable(false);
newstage.showAndWait();
}
public void clearStage () {
newstage.close();
}
If any mistaken so sorry since im just new to Java and i need to create a GUI for my project. Thanks for helping.
you need to add this:
newstage.initModality(Modality.APPLICATION_MODAL);
newstage.showAndWait();
see Modality
JavaFx has a various property that you can use, just it depends on the developer how he/she creative on his logic.
mainPane.setDisabled(true);
newPane.showAndWait();
Be advised that initModality() is broken and has been for a long time on the Linux platform runtime.
modal JavaFX stage initOwner prevents owner from resizing, bug?
Yes, that post directly refers to initOwner() but it's the call to initModality() that seems to trigger the bug. You can waste a lot of time playing with kludges that approximate the behavior you need but nothing seems to work just right.

JavaFX load one of fxml file depends on window

I'm totally new in JavaFX... Until now, for my basic app I had all in one class - Main class. Now I want to extend my app and do this in proper way, so I would like to make controllers. As far as I know, I need to put package of my controller in root element in FXML file.
In my case it is AnchorPane element and I put something like this:
fx:controller="hr.controller.MainWindowController"
And in this controller should be all injections for ID's and methods, right? By injections I mean #FXML annotation. But how I connect this with my Main class? What should be in Main class? I know (I thinks so :P) that Main should extends Application class. So it contains this method:
#Override
public void start(Stage stage) {}
What's more and what I said in the beginning I also want be able to load/open new window after some action. Let's say that I have file mainWindow.fxml with above reference to the controller. The second file window2.fxml should be loaded after action on button in the 1st window.
Could you tell me, how should I achive this?
UPDATE!
Main class:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("mainWindow.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root));
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MainWindowController:
public class MainWindowController{
#FXML
private Button btnSave;
#FXML
private MenuBar menuBar;
#FXML
private MenuItem exit;
#FXML
public void handleAction(ActionEvent event) throws IOException {
Stage stage = null;
Parent root = null;
if(event.getSource()==exit){
stage = (Stage) menuBar.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("window2.fxml"));
} else {
stage =(Stage) btnSave.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("mainWindow.fxml"));
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
Is this the proper way? It works how I want to, but I'm not sure if it should looks like this :)

How to return to code after I'm done with JavaFX scene

I'm launching my JavaFX scene as:
Applicaiton.launch(Main.class);
form my java code.
How to return to my code after I'm done with JavaFX!
Example:
public String Method()
{
Stirng s = "MyName";
Application.launch(Main.class);//here I lauch JavaFX scene
s.trim();//how to come back here after I'm done with that scene.
}
It's not supposed to work that way. You start by extending javafx.application.Application, then the entry point is start(Stage), which you must override. That method is the place where you have to set up the Scene for your stage, build the layout with Node's (buttons, layout managers, text fields, checkboxes), and register event handlers. You can access startup parameters with getParameters().
The application can be launched by providing the usual main() that calls launch(), a facility of JavaFX. So the minimal JavaFX application looks like:
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
VBox root = new VBox();
root.getChildren().setAll(new Label("Hello world!"));
Scene scene = new Scene(root, 600, 400);
// Add widgets and set up event handlers
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String... args) {
launch(args);
}
}
Platform.exit(); will do it click here for javafx2.2 documentation

Categories