How can I change the scene within the same window, rather than it opening a new window entirely.
Below is where the selectable options are added to a choicebox, with a listener at the end to "observe" when a selection is made, which, when clicked, changes the scene.
private void formulaOption2(){
list2.removeAll(list2);
String a = "Current Ratio";
String b = "Working Capital Ratio";
String c = "Debt to Equity Ratio";
String d = "Gross Profit Margin";
list2.addAll(a,b,c,d);
ChoiceBox2.getItems().addAll(list2);
//A LISTENER TO OBSERVE WHEN USER SELECTS ITEM
ChoiceBox2.getSelectionModel().selectedItemProperty().addListener( (v, oldValue, newValue) -> {
try {
comboSelect2();
} catch (IOException ex) {
Logger.getLogger(Tab1FXMLController.class.getName()).log(Level.SEVERE, null, ex);
}
} );
}
Below is the code that loads the FXML file:
public void comboSelect2() throws IOException {
if("Current Ratio".equals(ChoiceBox2.getSelectionModel().getSelectedItem())){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Tab2FXML.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Current Ratio");
stage.setScene(new Scene(root1));
stage.show();
}
}
Just replace the root of the current scene with the new root you want:
public void comboSelect2() throws IOException {
if("Current Ratio".equals(ChoiceBox2.getSelectionModel().getSelectedItem())){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Tab2FXML.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
ChoiceBox2.getScene().setRoot(root1);
}
}
Related
I dont know what is happening, Im trying to go back to the previous windows with some values already defined, but it doesnt work, I created an static ObservableList, so each time I add a new objective it will be added it, this part works, heres the code:
public void AddList(ActionEvent e) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Form.fxml"));
Parent root = loader.load();
Formcontroller = loader.getController();
Scene scene = new Scene(root);
Stage Newstage = (Stage)((Node)e.getSource()).getScene().getWindow();
Newstage.setScene(scene);
Newstage.show();
}
it will send me to the window where the form is, heres the code to add a new objective:
public void addObjective(ActionEvent e) throws IOException {
if (this.saving.getText().equalsIgnoreCase("")) {
Objectives object = new Objectives (this.objective.getText(), Double.parseDouble(this.price.getText()), 0);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Objectivescontroller = loader.getController();
controller.AgregarObjetivo(object);
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
Pstage.show();
}else {
if (Double.parseDouble(this.saving.getText()) != 0 || Double.parseDouble(this.saving.getText()) == 0) {
Objectives object = new Objectives (this.objective.getText(), Double.parseDouble(this.price.getText()), Double.parseDouble(this.saving.getText()));
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Objectivescontroller = loader.getController();
controller.addObjetive(object);
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
Pstage.show();
}
}
}
here is the code to add the objective to the list:
public void addObjective (Objectives objective) {
objectives.add(objective);
listview.getItems().addAll(objectives);
}
each new objectives that I add it will stay in the list, the problem now its that Im trying to make a button in the form window, where I can click on it and go back without adding a new objective, but it shows me the list empty, i dont know why it doesnt show me the list that is already with objectives, heres the code:
public void goback (ActionEvent e) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Objectives.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage Pstage = (Stage) button.getScene().getWindow();
Pstage.setScene(scene);
}
its the same code that I used to add new objective, the only difference its that Im not calling the controller, sorry if my code is ugly or noob, but Im new in java - javafx and im just starting, thanks!
This method(abc) is called when a button is pressed in the first scene. What it does is it changes the scene to waitingScreen and calls another method waitscr()
public void abc(ActionEvent event)throws Exception{
stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
//for changing the scene.
Parent administrator =
FXMLLoader.load(getClass().getResource("waitingScreen.fxml"));
stage.setScene(new Scene(administrator));
stage.show();
conn.close();
waiting_screen_Controller c = new waiting_screen_Controller();
c.waitscr(event);
What waitscr does is it starts a timer for 5 seconds and when the timer ends
it calls another method setscr() (maybe i could have started the timer in abc only)
public void waitscr(ActionEvent event)throws IOException{
timetask = new TimerTask(){
#Override
public void run() {
if(!timing){
try{
timetask.cancel();
setscr(event);
}
catch(Exception ex){
ex.printStackTrace();
}
}
else
timing = updateTime();
}
};
timer.scheduleAtFixedRate(timetask,1000,1000);
}
it updates the time
public boolean updateTime(){
System.out.println(s);
if(s==0){
return false;
}
s--;
return true;
}
what setscr does is it changes the scene back to the first one..
public void setscr(ActionEvent event)throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("first.fxml"));
Parent parent = loader.load();
Scene s=new Scene(parent);
stage = (Stage)((Node) event.getSource()).getScene().getWindow();
System.out.print(event.getSource());
stage.setScene(s);
stage.show();
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
But the problem is it gives npe in stage.
java.lang.NullPointerException
at sample.waiting_screen_Controller.setscr(waiting_screen_Controller.java:106)
at sample.waiting_screen_Controller$1.run(waiting_screen_Controller.java:45)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
I thought this was because of ActionEvent because npe is at stage but i printed the source of ActionEvent and it is not null.
You're replacing the scene before calling waitscr. This way when you call Scene.getWindow the scene is no longer associated with a window and the result is null.
You shouldn't do this from a non-application thread anyways.
By retrieving the window only once and using a Platform.runLater you should be able to fix this issue:
public void abc(ActionEvent event)throws Exception{
stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
...
c.waitscr(stage);
public void waitscr(final Stage stage) throws IOException {
timetask = new TimerTask(){
#Override
public void run() {
if(!timing){
try{
timetask.cancel();
setscr(stage);
} catch(Exception ex){
ex.printStackTrace();
}
}
else
timing = updateTime();
}
};
timer.scheduleAtFixedRate(timetask,1000,1000);
}
public void setscr(Stage stage)throws IOException{
// there seems to be a try missing somewhere
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("first.fxml"));
Parent parent = loader.load();
Scene s=new Scene(parent);
Platform.runLater(() -> {
// scene update on javafx application thread
stage.setScene(s);
stage.show();
});
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
I have two controllers. One controller manages most of the main functionality, the other controls a simple pop up prompt, accessed from the main controller.
This is the function stored in the main controller, used to access the prompt.
public void deletePrompt(){
DeletePromptController controller = new DeletePromptController();
boolean result = controller.showPrompt("/MainWindow//DeletePrompt.fxml");
if(result){
System.out.println("Deleted");
}else{
System.out.println("Canceled");
}
}
This is the prompt controller
public class DeletePromptController extends ShowWindow {
public Label question;
public Button delete, cancel;
private boolean result = true;
boolean showPrompt(String path){
showWindow(path);
return result;
}
public void delete(){
System.out.println("D");
result = true;
Stage stage = (Stage) delete.getScene().getWindow();
stage.close();
}
public void cancel(){
System.out.println("C");
result = false;
Stage stage = (Stage) cancel.getScene().getWindow();
stage.close();
}
}
And this is the block used to load and show the delete prompt fxml file.
public class ShowWindow {
public void showWindow(String path){
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(path));
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(new Scene(root));
stage.showAndWait();
}catch(IOException ex){
ex.printStackTrace();
}
}
}
Everything is working except one thing. The main controller when getting the result from the prompt controller is not getting the correct Boolean result.
Output when delete is pressed:
D
Canceled
Output when cancel is pressed:
C
Canceled
D should be followed by Deleted.
Anything helps.
FXMLLoader creates a new controller instance, since the fx:controller attribute is provided in the fxml.
You've basically got 2 options:
Remove the fx:controller attribute from the fxml and specify the controller yourself:
public void showWindow(String path){
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(path));
fxmlLoader.setController(this);
Parent root = fxmlLoader.load();
or
Get the controller created by the FXMLLoader
public static <T> T showWindow(String path){
try {
FXMLLoader fxmlLoader = new FXMLLoader(ShowWindow.class.getResource(path));
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(new Scene(root));
stage.showAndWait();
return fxmlLoader.getController();
}catch(IOException ex){
ex.printStackTrace();
}
return null;
}
boolean showPrompt(String path) {
return ShowWindow.<DeletePromptController>showWindow(path).result;
}
I have 2 controller for 2 fxml files. In one controller I have a handleOpen function which opens a file chooser and gives the path to a Class which I have called model. Then on the other controller a function, treeTableDraw gets this path, after clicking on Draw Button and runs the program. I have Another Button to reset the program. It sets the result back to null, but when open another file to run, the program crashes, because the path is null. How can I reset the program and make it use the new path which is selected from open file chooser?
//Gets the path from model and runs the program
public void treeTableDraw(ActionEvent event) {
new Controller(model.getText());
drawTable();
numberOfFunctions = dc.getFuncAll().size();
numberOfOrganizations = dc.getSortedAssignedOrg().size();
funcLabel.setText(numberOfFunctions + "");
orgLabel.setText(numberOfOrganizations + "");
btnDraw.setDisable(true);
}
/**
* Clrears TreeTableView and sets back labels
*
* #param event
*/
public void treeTableReset(ActionEvent event) {
btnDraw.setDisable(false);
model.setText(null);
funcLabel.setText("0");
orgLabel.setText("0");
treeTable.getColumns().clear();
}
This is RootLayout class which has open file function:
#FXML
private void handleOpen() {
FileChooser fileChooser = new FileChooser();
// Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(
"3lgm2 files (*.z3lgm)", "*z3lgm");
fileChooser.getExtensionFilters().add(extFilter);
// Show open file dialog
File file = fileChooser.showOpenDialog(main.getPrimaryStage());
if (file != null) {
path = file.toString();
model.setText(path);
}
}
Here is the model class
public class Model {
private final StringProperty text = new SimpleStringProperty();
public StringProperty textProperty() {
return text;
}
public final String getText() {
return textProperty().get();
}
public final void setText(String text) {
textProperty().set(text);
}
}
This is the main, where I combine two fxmls and set stage:
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private Model model = new Model();
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("IT-Saturation");
initRootLayout();
showOverView();
}
private void showOverView() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/view/OverView.fxml"));
loader.setController(new OverViewController(model));
AnchorPane overView = (AnchorPane) loader.load();
rootLayout.setCenter(overView);
} catch (IOException e) {
e.printStackTrace();
}
}
private void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/view/RootLayout.fxml"));
loader.setController(new RootLayoutController(model));
rootLayout = (BorderPane) loader.load();
// show scene containing the root layout
Scene scene = new Scene(rootLayout);
scene.getStylesheets().add(
getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
// gives controller access to main
RootLayoutController controller = loader.getController();
controller.setMainApp(this);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
*
* #return primaryStage
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
public void showMostComputerizedStatistics() {
try {
// Load the fxml file and create a new stage for the popup.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class
.getResource("view/BirthdayStatistics.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Birthday Statistics");
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the persons into the controller.
MostComputerizedController controller = loader.getController();
dialogStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The problem was not the path. I had to reset the data which got initialized at the the former run of program. So after setting path to null I just newed the instance of class which had reference to data.
...
public void treeTableReset(ActionEvent event) {
btnDraw.setDisable(false);
//model.setText(null);
funcLabel.setText("0");
orgLabel.setText("0");
treeTable.getColumns().clear();
dc = new DataConstructor();
}
I have made a simple JavaFX application, but I would like the main window to open a secondary window when the user clicks a button.
What would be the simplest way to accomplish this?
Button b = new Button();
b.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
Stage stage = new Stage();
//Fill stage with content
stage.show();
}
});
try this
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FXML.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
stage.show();
((Node) (event.getSource())).getScene().getWindow().hide();
} catch (Exception e) {
e.printStackTrace();
}