Opening a TabPane when button is clicked from another view - java

I have two separate views one which contains a button say view A and another a TabPane with 3 tabs call it view B. These two views are controlled by two separate view controller classes. I want to be able to click a button in view A and be able to to open a specific tab in view B's TabPane.
So far I have tried extending the controller for view A with view B such that I can get the TabPane defined in view B's controller then call myTabPane.getSelectionModel().select(myTab); however this hasn't worked as it throws a NullPointerException.
My question is it possible to click a button in view A such that it opens view B and opens a specific Tab on view B's TabPane.
I have also looked at these links with no luck 1. setting selected tab, 2. switch through tabs programatically, 3. switch between tabs in tabpane
Lets say the above image is view A and when u click right it should open view B and open a specific tab in view B's TabPane.
Lets say the above image is view B and when the button right on view A is clicked it should open view B and set the tab to tab C.
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.scene.control.SelectionModel;
public class SucessfulCreateProjectViewController extends AdminViewController {
#FXML
private Button OkButton;
#FXML
void handleCreateTasksButtonAction(ActionEvent event) {
try{
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("AdminView.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
AdminTabPane.getSelectionModel().select(1);;
}catch(Exception e){
ErrorHandlerController.infoBox("Error Opening AdminPage", "Fail", null);
e.printStackTrace();
}
}
#FXML
void handleOKButtonAction(ActionEvent event) {
Stage stage = (Stage) OkButton.getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
} }

Mediator is a design pattern that is used to communicate between objects that do not know each other.
This is an example of a mediator that would have done your job.
public class Mediator {
private static Mediator instance;
private Consumer<String> consumer;
public static Mediator getInstance() {
if(instance == null) {
instance = new Mediator();
}
return instance;
}
private Mediator() {
}
public void register(Consumer<String> consumer) {
this.consumer = consumer;
}
public void fireEvent(String string) {
if(consumer != null) {
consumer.accept(string);
}
}
}
and respectively, the two controllers
public class ViewAController {
#FXML
private Button btnL, btnR;
#FXML
private void initialize() {
btnL.setOnAction(event -> Mediator.getInstance().fireEvent("left"));
btnR.setOnAction(event -> Mediator.getInstance().fireEvent("right"));
}
}
public class ViewBController {
#FXML
private TabPane tabPane;
#FXML
private void initialize() {
Mediator.getInstance().register(s -> {
switch (s) {
case "left":
tabPane.getSelectionModel().select(0);
break;
case "right":
tabPane.getSelectionModel().select(2);
break;
}
});
}
}
and this is a test application that opens two windows at once.
public class Main extends Application {
#Override
public void start(Stage stageA) throws Exception{
Parent viewA = FXMLLoader.load(getClass().getResource("view_a.fxml"));
Parent viewB = FXMLLoader.load(getClass().getResource("view_b.fxml"));
stageA.setTitle("View A");
stageA.setScene(new Scene(viewA));
stageA.show();
Stage stageB = new Stage();
stageB.setTitle("View B");
stageB.setScene(new Scene(viewB));
stageB.show();
}
public static void main(String[] args) {
launch(args);
}
}
if you do not want to use two windows at once, just change the middleman.

Related

JavaFX actions on elements of one window from another window

Please help me solve the problem. There are two fxml files and their controllers:
sample.fxml, its controller ControllerMain (main window of the program)
find_win.fxml, its ControllerFind controller (modal window "text search")
In the modal window find_win.fxml there is a TextField into which the search text is entered, and the Find button, when clicked, ControllerFind must process the click and call the search method and highlight the search text in the TextArea element of the sample.fxml window.
<fx: include source = "sample.fxml" fx: id = "textAreaOne" />
and the inheritance of the ControllerMain by the ControllerFind controller does not help to achieve a solution - in the first case the entire window markup is included in the modal window completely, in the second case, the java.lang.reflect.InvocationTargetException is returned during an operation on the TextArea.
How to implement actions on elements of one window from another window?
I've found a solution elsewhere. Thanks to Comrade Antizam, who tried to help, but did not quite understand what I needed.
The solution described here is .
In short, it is necessary to create an instance of a controller-parent and a method that takes an instance of a controller-parent as a parameter in the controller-child. When a new window is opened from a controller-parent, get an instance of the controller-child and indicate to it through the created method "this".
Further, in the controller-child, it will be possible to access the elements of the parent controller.
controller-parent:
package sample;
public class ControllerMain {
private ControllerFind children; // controller-child
//main-window
#FXML
public TextArea textAreaOne;
#FXML
public MenuItem findMenuItem;
public void findAction(ActionEvent actionEvent) {
try {
Stage stageFind = new Stage();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/find_win.fxml"));
Parent root = loader.load();
stageFind.setTitle("Find");
stageFind.setMinHeight(200);
stageFind.setMinWidth(150);
stageFind.setResizable(false);
stageFind.setScene(new Scene(root));
stageFind.getIcons().add(new Image("image/search.png"));
stageFind.initModality(Modality.NONE);
stageFind.show();
children = loader.getController(); //getting controller of window find_win.fxml
children.setParent(this); //setting parent of the controller-child - this
} catch (IOException e) {
e.printStackTrace();
}
}
}
controller-child:
package sample.Controllers;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import sample.Classes.DialogManager;
import sample.ControllerMain;
public class ControllerFind {
//Window "Find"
#FXML public TextField searchTextField;
#FXML public Label findTextLabel;
#FXML public Button okTextFindButton;
#FXML public Button cancelTextFindButton;
private String text;
private ControllerMain controller;
public void setParent (ControllerMain controller){
this.controller = controller;
}
public ControllerFind getThis(){
return this;
}
public void initialize(){
System.out.println("psvm");
}
public void textFindOkButtonAction(ActionEvent actionEvent) {
text = (searchTextField.getText());
if (text.equals("")) {
DialogManager.showInfoDialog("Error!", "Enter text what you are looking for!");
} else {
if (controller.textAreaOne.getText() != null && !controller.textAreaOne.getText().isEmpty()) {
int index = controller.textAreaOne.getText().indexOf(text);
if (index == -1) {
DialogManager.showInfoDialog("Result", "There isn't text what you are looking for");
} else {
controller.textAreaOne.selectRange(index, index + text.length());
}
} else {
DialogManager.showInfoDialog("Error", "TextArea is empty!");
}
}
}
public void textFindCancelButtonAction(ActionEvent actionEvent) {
Node source = (Node) actionEvent.getSource();
Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
Vis-a-vis windows communication in this situation, it's optimal to use TextInputDialog something like this:
#Override
public void start(Stage primaryStage){
Button btn=new Button("Click");
VBox vbox=new VBox();
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(btn);
Scene scene=new Scene(vbox, 200,200);
btn.setOnAction(e->
{
TextInputDialog dialog=new TextInputDialog();
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
System.out.println(result.get());
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
but text highlighting is not something that can be done easy.
You could do String search of TextArea text, compare it to result from another window then highlight it via
textArea.getSelectedRange(firstIndex, lastIndex);
firstIndex and lastIndex being indexes of textArea text for the word we are searching. Then having button on every click displaying next word occurancy inside text and highlighting it. But if you insist on highlighting every instance of word at the same time I would suggest using RichTextFX.

Items replacing but not asked

I'm working on a little game. So I create the game interface (countains the gun, the canvas which I use as gamespace and an interface for the user to control is gun). I place the different elements in the window and there is my problem. When I execute my code, all is well placed but once I use one of the buttons (buttons in both codes) or the slider (second code), the slider and the fire button replace themselves. And I don't understand why because I never asked this rellocation in my code. Also, when the items rellocate, I can't use any other items excepted the fire button and the slider.
Here are screenshots of what I have before using a button (first screenshot) (it's also how I want the interface to be) and the second screenshot shows the rellocation I have.
How it looks when I use nothing.
How it looks when I use a button or the slider.
Main.java :
package application;
import bureaux.Bureau;
import canons.Canon;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ToolBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Main extends Application{
private StackPane root, rootBureau;
private Scene scene;
private Stage stage;
private Text joueur;
private Button menu, musique, ajoutJoueur;
private FlowPane rootJeu;
private Bureau bureauJoueur;
private ToolBar toolBar;
private Canon canonJoueur;
#Override
public void start(Stage primaryStage) throws IOException {
getRoot();
getScene();
stage = primaryStage;
creerInterface();
stage.setTitle("Mad Java Guns");
stage.setResizable(false);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public void creerInterface(String mode) { // creating the gamespace and the objects that the user need to play
getToolBar().getItems().addAll(getMusique(), getAjoutJoueur());
getRootBureau().getChildren().add(getBureauJoueur());
getRootJeu().getChildren().add(getCanonJoueur());
getRoot().getChildren().addAll(getToolBar(), getJoueur(), getRootBureau(), getRootJeu());
}
// Getters
public StackPane getRoot() {
if(root == null) {
root = new StackPane();
}
return root;
}
public Scene getScene() {
if(scene == null) {
scene = new Scene(root,1000,800);
}
return scene;
}
public Text getJoueur() { // gamespace
if(joueur == null) {
joueur = new Text("Espace de jeu");
joueur.setFont(Font.font("Arial", 20));
joueur.setTranslateY(120);
}
return joueur;
}
public ToolBar getToolBar() {
if(toolBar == null) {
toolBar = new ToolBar();
toolBar.setTranslateY(122);
toolBar.setTranslateX(3);
toolBar.setStyle("-fx-background-color: transparent");
}
return toolBar;
}
public Button getMusique() { // button too change the music in game
if (musique == null) {
musique = new Button("Musique");
musique.setOnMouseClicked(e -> {
System.out.println("musique"); // not coded yet
});
musique.setFocusTraversable(false);
}
return musique;
}
public Button getAjoutJoueur() { // add players in the game
if(ajoutJoueur == null) {
ajoutJoueur = new Button("Ajouter un joueur");
ajoutJoueur.setOnMouseClicked(e -> {
System.out.println("ajoutJoueur"); //not coded yet
});
ajoutJoueur.setFocusTraversable(false);
}
return ajoutJoueur;
}
public StackPane getRootBureau() { // pane where the user's interface will be placed
if(rootBureau == null) {
rootBureau = new StackPane();
rootBureau.setStyle("-fx-background-color: lightgrey");
rootBureau.setMaxSize(990, 250);
rootBureau.setTranslateY(270);
}
return rootBureau;
}
public Bureau getBureauJoueur() { // user's interface
if(bureauJoueur == null) {
bureauJoueur = new Bureau("Billy", getCanonJoueur());
}
return bureauJoueur;
}
}
Class Bureau.java :
package bureaux;
import canons.Canon;
import javafx.geometry.Orientation;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class Bureau extends Parent {
private Slider sliderCanon;
private HBox boxPrincipale;
private VBox boxControlesCanon;
private Button feu;
public Bureau(String nom, Canon canon) {
getBoxControlesCanon().getChildren().addAll(getSliderCanon(), getFeu());
getBoxPrincipale().getChildren().add(getBoxControlesCanon());
this.setTranslateX(-480); // placing the boxes
this.setTranslateY(-95);
this.getChildren().add(getBoxPrincipale());
}
//Getteurs
public HBox getBoxPrincipale() {
if(boxPrincipale == null) { // return a HBox which countains the VBox (next function)
// and other elements which aren't created yet.
boxPrincipale = new HBox();
}
return boxPrincipale;
}
public VBox getBoxControlesCanon() { // return a VBox which countains the controls of the gun
//(gun not showed in the code, doesn't concern the problem)
if(boxControlesCanon == null) {
boxControlesCanon = new VBox();
boxControlesCanon.setSpacing(20);
}
return boxControlesCanon;
}
public Slider getSliderCanon() { //slider to orient the gun (gun not showed in the code, doesn't concern the problem)
if(sliderCanon == null) {
sliderCanon = new Slider(0, 360, 0);
sliderCanon.setOrientation(Orientation.VERTICAL);
sliderCanon.valueProperty().addListener(e -> {
System.out.println(sliderCanon.getValue());
});
sliderCanon.setShowTickMarks(true);
sliderCanon.setShowTickLabels(true);
sliderCanon.setMajorTickUnit(90f);
}
return sliderCanon;
}
public Button getFeu() { // fire button
if(feu == null) {
feu = new Button("Feu");
feu.setOnMouseClicked(e -> {
System.out.println("Feu");
});
feu.setFocusTraversable(false);
}
return feu;
}
}
Please ask for more informations if necessary. Thanks for your help.
EDIT : sorry for the unpoliteness on top of this text, I used to edit it and add "Hello" but it just don't want to show it :/
You are using Bureau extends Parent. You will have to be more specific and used the nodes that will produce the outcome you need.
Try something like Bureau extends HBox. Then
getBoxControlesCanon().getChildren().add(new VBox(getSliderCanon(), getFeu()));
To get the left alignment, you may need to do something like
getBoxControlesCanon().getChildren().addAll(new VBox(getSliderCanon(), getFeu()), someOtherNode);
HBox.setHGrow(someOtherNode, Priority.ALWAYS);
If you look at Parent compared to VBox, you will see that Parent does not describe how children nodes will be laid out. A lot of nodes that are a subclass of Parent do describe how their children nodes will be laid out.

JavaFX TableColumn nullpointerexception [duplicate]

I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.

javafx using objects from MainController or other Controllers in proper Controller class

I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.

Adding a change listener to JavaFX ToggleSwitch

My stage contains a ToggleSwitch and two StackPanes which we'll call A and B. Both StackPanes are located in the same space within the parent StackPane. This means that if both A and B are visible and set to managed, they each take up half the allocated space like this:
I'm trying to hide StackPane B upon initalization so that StackPane A takes up the full space... and then when I click the toggle button, it should hide StackPane A and show StackPane B, making B take up the full space.
The initial hiding of StackPane B works fine, but I'm having trouble writing a change listener for the ToggleSwitch in my controller class. Here is my code, and where I'm having trouble:
application class:
public class showPanes extends Application {
Stage stage = new Stage();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
StackPane root = (StackPane) FXMLLoader.load(Drag.class.getResource("twoPanes.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Pane Switcher");
scene.getStylesheets().add("styleMain.css");
stage.setScene(scene);
stage.show();
}
}
The answer found here uses Toggle Groups, and James' answer here uses Buttons. I can't find a solution for ToggleSwitch. I tried to adapt the first answer for use with ToggleSwitch but it's producing an error like:
and says
Cannot resolve method 'addListener(anonymous
javafx.beans.value.ChangeListener)'
How do I fix the listener?
controller class:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import java.net.URL;
import java.util.ResourceBundle;
import org.controlsfx.control.ToggleSwitch;
public class compsController implements Initializable {
#FXML
private StackPane paneA, paneB;
#FXML
private ToggleSwitch toggleSwitch;
#Override
public void initialize(URL location, ResourceBundle resources) {
paneB.setManaged(false);
paneB.setVisible(false);
toggleSwitch.selectedProperty().addListener(new ChangeListener < ToggleSwitch > () {
#Override
public void changed(ObservableValue < ? extends ToggleSwitch > ov, ToggleSwitch t, ToggleSwitch t1) {
paneA.setManaged(false);
paneA.setVisible(false);
paneB.setManaged(true);
paneB.setVisible(true);
}
});
}
}
You could also use the Binding API of JavaFx like below,
#Override
public void initialize(URL location, ResourceBundle resources) {
paneA.managedProperty().bind(toggleSwitch.selectedProperty());
paneA.visibleProperty().bind(toggleSwitch.selectedProperty());
paneB.managedProperty().bind(toggleSwitch.selectedProperty().not());
paneB.visibleProperty().bind(toggleSwitch.selectedProperty().not());
}
}

Categories

Resources