I am building an JavaFX application and am want to access values passed as an argument within the JavaFX UI. For some reason, I am unable to access these values in all the methods except the base method launchForm. Here is what my code looks like.
public class FormBuilder extends Application {
/*
* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
* Scene scene
* Group root
* BorderPane borderPane
* TabPane tabPane
* Tab stocksTab
* BorderPane stockTabBorderPane
* GridPane gridPane
*
*/
private Stocks stockData = new Stocks();
private int size;
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Stock Manager");
Group root = new Group();
Scene scene = new Scene(root, 1024, 800, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
BorderPane stockTabBorderPane = new BorderPane();
Tab stocksTab = new Tab("Stocks");
stockTabBorderPane.setTop(this.addHBox());
stockTabBorderPane.setCenter(this.createGridPane());
stocksTab.setContent(stockTabBorderPane);
tabPane.getTabs().add(stocksTab);
borderPane.setCenter(tabPane);
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
root.getChildren().add(borderPane);
stage.setScene(scene);
stage.show();
}
private HBox addHBox() {
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
hbox.setStyle("-fx-background-color: #336699;");
Button buttonCurrent = new Button("Current");
buttonCurrent.setPrefSize(100, 20);
Button buttonProjected = new Button("Projected");
buttonProjected.setPrefSize(100, 20);
hbox.getChildren().addAll(buttonCurrent, buttonProjected);
return hbox;
}
private GridPane createGridPane() {
GridPane gridPane = new GridPane();
gridPane.setLayoutX(39);
gridPane.setLayoutY(131.0);
gridPane.setAlignment(Pos.TOP_CENTER);
gridPane.setVgap(5.0);
gridPane.setHgap(10.0);
gridPane.add(new Label("Active"), 1,1);
gridPane.add(new Label("Stock"), 2, 1);
gridPane.add(new Label("Symbol"), 3, 1);
gridPane.add(new Label("LPP"), 4, 1);
gridPane.add(new Label("LPP"), 5, 1);
gridPane.add(new Label("HPP"), 6, 1);
gridPane.add(new Label("LTP"), 7, 1);
System.out.println(this.size);
for(int v=2;v < this.stockData.getStocks().size()+2; v++) {
gridPane.add(new CheckBox(), 1, v);
gridPane.add(new Label("Amazon"), 2, v);
gridPane.add(new TextField (), 3,v);
gridPane.add(new TextField (), 4,v);
gridPane.add(new TextField (), 5,v);
gridPane.add(new TextField (), 6,v);
gridPane.add(new TextField (), 7,v);
}
return gridPane;
}
public void launchForm(Stocks stockData) {
this.stockData = stockData;
this.size = stockData.getStocks().size();
System.out.println(stockData.getStocks().size());
System.out.println(stockData.getStocks().get(0).getSector());
launch();
}
}
Now the issue is that when I try and access any value under the stockData object within the createGridPane method, the values are not available.
Examples are
this.stockData.getStocks().size() gives the value of 0 in the createGridPane method. But it gives a value of 2 in the launchForm method.
Again there are other values like
this.stockData.getStocks().get(0).getSector()
which returns the value "Retail" in the launchForm method. But when I try to access the same in a different method in the same class, I get an exception.
Can someone please help me here?
You're invoking Application.launch in the launchForm instance method and expect it to use the instance this method is invoked for as application class.
The JavaFX launch does not work this way however.
If Application.launch is called, a new instance of the class the method is invoked from is created by the launch method itself and it is this new instance that is used with init and start.
The easiest way to fix this would be, if you could create the Stocks in the init or start (possibly passing some Strings as parameters to launch).
Otherwise you need some other way to communicate with the newly created instance of the Application subclass, e.g. static members...
In JavaFX you should basically consider the Application subclass, and in particular its start() method, to be the entry point of the application. The application lifecycle is described in the Application Javadocs, but in brief the JavaFX launch process is initiated either by calling one of the static Application.launch(...) methods, or (using the Oracle JDK) by launching the JVM and specifying an Application subclass as the main class (even if it doesn't have a main method).
The launch process then:
starts the JavaFX toolkit
creates a new instance of the Application subclass
invokes init() on the Application subclass (the default implementation is a no-op)
starts the FX Application Thread
invokes start() on the Application subclass, executing it on the FX Application Thread.
Despite being invoked on different threads, start() is guaranteed not to be invoked until init() has completed.
From the code you posted, it must be the case that you are instantiating your FormBuilder class somewhere else, and calling launchForm(...) on that instance. When you call launch() from there, that creates a second instance and invokes start() on it, as described above. So of course the fields that you set on the instance on which launchForm(...) is called will not be set on the instance on which start(...) is called.
You should refactor your code so that either FormBuilder is the entry point to the application, or make FormBuilder not be an Application subclass and create a new entry point that instantiates and uses it. It appears you have some background work which loads data: this should be a separate class which should not be the entry point. So the first refactoring would look like:
// class that reads data and encapsulates it as a Stocks object
public class StockDataAccessor {
// ...
public Stocks getStocks() {
// ...
}
}
Then FormBuilder looks like:
public class FormBuilder extends Application {
/*
* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
* Scene scene
* Group root
* BorderPane borderPane
* TabPane tabPane
* Tab stocksTab
* BorderPane stockTabBorderPane
* GridPane gridPane
*
*/
private Stocks stockData ;
private int size;
#Override
public void start(Stage stage) throws Exception {
StockDataAccessor stockDataAccessor = new StockDataAccessor();
stockData = stockDataAccessor.getStocks();
stage.setTitle("Stock Manager");
Group root = new Group();
Scene scene = new Scene(root, 1024, 800, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
BorderPane stockTabBorderPane = new BorderPane();
Tab stocksTab = new Tab("Stocks");
stockTabBorderPane.setTop(this.addHBox());
stockTabBorderPane.setCenter(this.createGridPane());
stocksTab.setContent(stockTabBorderPane);
tabPane.getTabs().add(stocksTab);
borderPane.setCenter(tabPane);
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
root.getChildren().add(borderPane);
stage.setScene(scene);
stage.show();
}
private HBox addHBox() {
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
hbox.setStyle("-fx-background-color: #336699;");
Button buttonCurrent = new Button("Current");
buttonCurrent.setPrefSize(100, 20);
Button buttonProjected = new Button("Projected");
buttonProjected.setPrefSize(100, 20);
hbox.getChildren().addAll(buttonCurrent, buttonProjected);
return hbox;
}
private GridPane createGridPane() {
GridPane gridPane = new GridPane();
gridPane.setLayoutX(39);
gridPane.setLayoutY(131.0);
gridPane.setAlignment(Pos.TOP_CENTER);
gridPane.setVgap(5.0);
gridPane.setHgap(10.0);
gridPane.add(new Label("Active"), 1,1);
gridPane.add(new Label("Stock"), 2, 1);
gridPane.add(new Label("Symbol"), 3, 1);
gridPane.add(new Label("LPP"), 4, 1);
gridPane.add(new Label("LPP"), 5, 1);
gridPane.add(new Label("HPP"), 6, 1);
gridPane.add(new Label("LTP"), 7, 1);
System.out.println(this.size);
for(int v=2;v < this.stockData.getStocks().size()+2; v++) {
gridPane.add(new CheckBox(), 1, v);
gridPane.add(new Label("Amazon"), 2, v);
gridPane.add(new TextField (), 3,v);
gridPane.add(new TextField (), 4,v);
gridPane.add(new TextField (), 5,v);
gridPane.add(new TextField (), 6,v);
gridPane.add(new TextField (), 7,v);
}
return gridPane;
}
// for non-JavaFX aware environments (like your IDE...)
public static void main(String[] args) {
launch(args);
}
}
Then launching FormBuilder as your main class will do what you need.
If you want to factor the application entry point out of the FormBuilder class entirely, the alternative refactoring (which is pretty similar) looks like:
public class FormBuilder {
/*
* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
* Scene scene
* Group root
* BorderPane borderPane
* TabPane tabPane
* Tab stocksTab
* BorderPane stockTabBorderPane
* GridPane gridPane
*
*/
private Stocks stockData ;
private int size;
private Group root ;
public FormBuilder() {
StockDataAccessor stockDataAccessor = new StockDataAccessor();
stockData = stockDataAccessor.getStocks();
root = new Group();
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
BorderPane stockTabBorderPane = new BorderPane();
Tab stocksTab = new Tab("Stocks");
stockTabBorderPane.setTop(this.addHBox());
stockTabBorderPane.setCenter(this.createGridPane());
stocksTab.setContent(stockTabBorderPane);
tabPane.getTabs().add(stocksTab);
borderPane.setCenter(tabPane);
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
root.getChildren().add(borderPane);
}
public Parent getView() {
return root ;
}
private HBox addHBox() {
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
hbox.setStyle("-fx-background-color: #336699;");
Button buttonCurrent = new Button("Current");
buttonCurrent.setPrefSize(100, 20);
Button buttonProjected = new Button("Projected");
buttonProjected.setPrefSize(100, 20);
hbox.getChildren().addAll(buttonCurrent, buttonProjected);
return hbox;
}
private GridPane createGridPane() {
GridPane gridPane = new GridPane();
gridPane.setLayoutX(39);
gridPane.setLayoutY(131.0);
gridPane.setAlignment(Pos.TOP_CENTER);
gridPane.setVgap(5.0);
gridPane.setHgap(10.0);
gridPane.add(new Label("Active"), 1,1);
gridPane.add(new Label("Stock"), 2, 1);
gridPane.add(new Label("Symbol"), 3, 1);
gridPane.add(new Label("LPP"), 4, 1);
gridPane.add(new Label("LPP"), 5, 1);
gridPane.add(new Label("HPP"), 6, 1);
gridPane.add(new Label("LTP"), 7, 1);
System.out.println(this.size);
for(int v=2;v < this.stockData.getStocks().size()+2; v++) {
gridPane.add(new CheckBox(), 1, v);
gridPane.add(new Label("Amazon"), 2, v);
gridPane.add(new TextField (), 3,v);
gridPane.add(new TextField (), 4,v);
gridPane.add(new TextField (), 5,v);
gridPane.add(new TextField (), 6,v);
gridPane.add(new TextField (), 7,v);
}
return gridPane;
}
}
and then create an entry point:
public class StockApp extends Application {
#Override
public void start(Stage stage) {
FormBuilder formBuilder = new FormBuilder();
Scene scene = new Scene(formBuilder.getView(), 1024, 800, Color.WHITE);
stage.setTitle("Stock Manager");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I was working on JavaFX, and I realised something which kept me thinking. So, there's a scene in my constructor which adds the variable root of the type BorderPane. In the main class, this class' constructor is called first, thereby initialising the BorderPane in the Scene. However, the BorderPane is being modified and edited in a method called build. I am confused how the BorderPane is still being able to display its updated version from the build() since in the constructor it has already been commanded to display.
Here's my code:
public class SnacksOrDrinks
{
private BorderPane root;
private Stage primaryStage;
private Scene scene;
private Cart crt;
public SnacksOrDrinks(Stage primaryStage, Cart crt)
{
// BorderPane is being initialised and is being put inside the scene:
BorderPane root1 = new BorderPane();
this.scene = new Scene(root1, 800, 475);
this.crt = crt;
ImageView imgview = new ImageView("./application/MountainPainting.jpg");
imgview.fitWidthProperty().bind(primaryStage.widthProperty());
imgview.fitHeightProperty().bind(primaryStage.heightProperty());
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
this.primaryStage = primaryStage;
this.root = root1;
root.setStyle("-fx-background-color: blue");
root.getChildren().add(imgview);
}
public void build(Dispenser dis)
{
// ItemsPaneProp extends GridPane and stores the common properties shared in other classes.
ItemsPaneProp pane = new ItemsPaneProp();
// Header Created:
CommHeaderProp header = new CommHeaderProp("Lopes Vending Machine");
// However, BorderPane is being modified here, and the constructor has already been called.
BorderPane.setAlignment(header, Pos.CENTER);
root.setTop(header);
// Create a Line:
Line line = new Line(100, 10, 300, 10);
line.setFill(Color.GOLDENROD);
line.setStrokeWidth(2);
line.setSmooth(true);
pane.add(line, 0, 0);
// Create all the Scene's Components and setup the Event Handlers
ImageView img = new ImageView("./application/softdrink.jpg");
img.setFitWidth(75);
img.setFitHeight(75);
Button btn1 = new Button("Select to get Drinks", img);
btn1.setStyle("-fx-background-color: white");
btn1.setFont(Font.font("Times New Roman", FontWeight.BOLD, FontPosture.REGULAR, 12));
btn1.setContentDisplay(ContentDisplay.TOP);
pane.add(btn1, 0, 1);
ImageView img1 = new ImageView("./application/potato-chips.png");
img1.setFitWidth(75);
img1.setFitHeight(75);
Button btn2 = new Button("Select to get Snacks", img1);
btn2.setStyle("-fx-background-color: white");
btn2.setFont(Font.font("Times New Roman", FontWeight.BOLD, FontPosture.REGULAR, 12));
btn2.setContentDisplay(ContentDisplay.TOP);`enter code here`
pane.add(btn2, 1, 1);
root.setCenter(pane); // The BorderPane is being modified here too, but the constructor isn't updating the scene. Then, how does it still work?
btn1.setOnMouseClicked(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent e)
{
// Create, build, and show Scene 2
DrinksList scene = new DrinksList(primaryStage, crt);
scene.build(dis);
scene.show();
}
});
btn2.setOnMouseClicked(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent e)
{
// Create, build, and show Scene 2
SnacksList scene = new SnacksList(primaryStage, crt);
scene.build(dis);
scene.show();
}
});
}
public void show()
{// setting scene:
primaryStage.setScene(scene);
}
}
Take a look at https://docs.oracle.com/javase/8/javafx/scene-graph-tutorial/scenegraph.htm#JFXSG107
The JavaFX scene graph is a retained mode API, meaning that it maintains an internal model of all graphical objects in your application. At any given time, it knows what objects to display, what areas of the screen need repainting, and how to render it all in the most efficient manner.
Your borderPane - part of SceneGraph, so JavaFX knows, when you change anything in your borderPane, and automatically invoking redraw method for it.
I am testing the JavaFX ScrollPane class and realized that it is not working as I expect, I don't know why. I have the following code:
public class Client3 extends Application {
int indexMsg = 0;
Button send;
GridPane root;
ScrollPane msgPane;
GridPane msgPaneContent;
FlowPane writePane;
TextField writeMsg;
Scene scene;
#Override
public void start(Stage primaryStage) {
root = new GridPane();
root.setAlignment(Pos.CENTER);
root.setVgap(10);
root.setPadding(new Insets(10, 10, 10, 10));
msgPane = new ScrollPane();
msgPane.setPrefSize(280, 280);
msgPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
msgPaneContent = new GridPane();
msgPaneContent.setPrefWidth(270);
msgPaneContent.setVgap(10);
writePane = new FlowPane(10, 10);
writePane.setAlignment(Pos.CENTER);
writePane.setPrefWidth(280);
writeMsg = new TextField();
writeMsg.setPrefWidth(150);
writeMsg.setPromptText("Write your message");
writePane.getChildren().add(writeMsg);
GridPane.setConstraints(msgPane, 0, 0);
GridPane.setConstraints(writePane, 0, 1);
msgPane.setContent(msgPaneContent);
root.getChildren().addAll(msgPane, writePane);
writeMsg.setOnAction((ev) -> {
if (!writeMsg.getText().isEmpty()) {
TextArea msg = new TextArea(writeMsg.getText());
msg.setMaxWidth(135);
msg.setPrefRowCount(msg.getLength() / 21 + 1);
msg.setWrapText(true);
GridPane.setConstraints(msg, 0, indexMsg);
indexMsg++;
writeMsg.deleteText(0, writeMsg.getText().length());
msgPaneContent.getChildren().add(msg);
msgPane.setVvalue(1.0);
}
});
scene = new Scene(root, 300, 300);
primaryStage.setTitle("Chat App");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Basically, I have a GridPane as the root with a ScrollPane and a GridPane as its children. The ScrollPane has a children GridPane. There is a TextField with an EventHandler which generates a TextArea inside the GridPane (the ScrollPane's children). Each TextArea object is created in the vertical direction, downwards. I want to set the scrollbar always at its maximum value (setVvalue(1.0)) each time a new TextArea is added. The thing is that it doesn't seem to work as it should because the vertical value is never set to the maximum after handling the event, but it seems to be set to the maximum value that it had before handling it (the bottom of the previous TextArea added).
Any solution for this? Thanks in advance.
I would like to declare a JavaFX GridPane of two panels, the left one containing a push button. When the push button is clicked a LineChart is displayed in the right hand panel. The coding would presumably look like this:
public class FormLineChart extends Application {
#Override
public void start(Stage stage) {
stage.setTitle("A Title");
//Create the grid for defining the GUI
GridPane grid = new GridPane();
// add gui objects to grid
...
//Create the chart
final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
...
// Create the series and display the lineChart
lineChart.getData().add(series);
stage.setScene(scene);
Scene scene = new Scene(grid, 427, 319);
//How do we add 'lineChart' to scene as well as keeping 'grid'?
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Specifically is it possible to combine 'grid' and 'lineChart' in one scene? At the moment only the GUI is displayed because on is forced to set the scene to the grid.
As #James_D said you simply need another container to achieve that. A Pane can contain GUI controls as well as another Pane.
In the example below I put a GridPane with few buttons inside a BorderPane that divides the window into right and left part.
#Override
public void start(Stage stage) {
stage.setTitle("A Title");
// Root element
BorderPane root = new BorderPane();
// GridPane
GridPane grid = new GridPane();
grid.setPadding(new Insets(10,10,10,10));
grid.setVgap(10);
grid.add(new Button("Button 1"), 0, 0);
grid.add(new Button("Button 2"), 0, 1);
grid.add(new Button("Button 3"), 0, 2);
// Chart
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
XYChart.Series series = new XYChart.Series();
series.setName("Chart");
series.getData().add(new XYChart.Data(1, 5));
series.getData().add(new XYChart.Data(2, 10));
lineChart.getData().add(series);
root.setLeft(grid);
root.setRight(lineChart);
Scene scene = new Scene(root, 600, 300);
stage.setScene(scene);
stage.show();
}
I want to display another layout in another window, but whenever I add a new layout to start method
BorderPane sch = new BorderPane();
sch.setCenter(addVBox2(primaryStage));
scene1 = new Scene(sch, 800, 500);
I get this error
Exception in Application start method
Exception in thread "main" **java.lang.NoSuchMethodException**: sample.Main.main([Ljava.lang.String;)
at java.lang.Class.getMethod(Class.java:1786)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:119)
Where might the problem in the code be? Thank you for any help in advance.
public void start(Stage primaryStage) throws IOException {
stage = primaryStage;
BorderPane border = new BorderPane();
border.setLeft(addVBox(primaryStage));
border.setCenter(addGridPane(primaryStage));
border.setRight(addDatePicker(primaryStage));
HBox hbox = addHBox();
border.setBottom(hbox);
scene = new Scene(border, 800, 500);
BorderPane sch = new BorderPane();
sch.setCenter(addVBox2(primaryStage));
scene1 = new Scene(sch, 800, 500);
stage.setScene(scene);
stage.setTitle("Booking Form");
stage.show();
}
private VBox addVBox2(Stage stage) {
javafx.scene.control.Label label = new javafx.scene.control.Label("Choose rooms' schedule");
label.setFont(javafx.scene.text.Font.font("Tahoma", FontWeight.BOLD, 16));
room1 = new RadioButton("Room 1 of type 1");
room1.setSelected(true);
room2 = new RadioButton("Room 2 of type 1");
room3 = new RadioButton("Room 1 of type 2");
room4 = new RadioButton("Room 2 of type 2");
room5 = new RadioButton("Room 1 of type 3");
room6 = new RadioButton("Room 2 of type 3");
VBox buttons2 = new VBox(20, label, roomtype1, roomtype2);
buttons2.setAlignment(Pos.CENTER);
buttons2.setMaxWidth(225);
stackPane.getChildren().add(buttons2);
ToggleGroup toggleGroup = new ToggleGroup();
toggleGroup.getToggles().addAll(roomtype1, roomtype2);
Scene scene = new Scene(stackPane, 400, 200);
stage.setTitle("RadioButton control");
stage.setScene(scene);
stage.show();
return buttons2;
}
private HBox addHBox() {
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10); // Gap between nodes
hbox.setStyle("-fx-background-color: #336699;");
hbox.setAlignment(Pos.CENTER);
final Text actionTarget = new Text();
Button schedule = new Button("Schedule");
schedule.setPrefSize(100, 20);
schedule.setOnAction(e -> stage.setScene(scene1));
...}
Exception in thread "main" java.lang.NoSuchMethodException: Main.main([Ljava.lang.String;)
This error means your main class is not found. When you have this kind of error, most of the time it means you moved your main class from a file to another without changing your run configuration.
Edit your run configuration in intellij IDE. Your run configuration is pointing to wrong class it seems. edit run configuration
I am having a resize issue when content is added and removed from a JavaFX BorderPane. The BorderPane content is not being resized until the window is manually resized. I have written a small test app to model this behavior. The application builds a BorderPane that contains a rectangle embedded within a StackPane at the center of the BorderPane. Along the bottom of the BorderPane there is a VBox and HBox that contain text and a separator. There is a menu item that removes the content from the bottom of the BorderPane (MoveText -> Right) and adds similar content to the right position of the BorderPane.
When the text is added to the right position of the BorderPane, the rectangle overlaps the text. In otherwords the content of the BorderPane center is overlapping the content in the BorderPane right.
I saw the following link -
https://stackoverflow.com/questions/5302197/javafx-bug-is-there-a-way-to-force-repaint-this-is-not-a-single-threading-pr
Calling requestLayout does not seem to help. I have also tried calling impl_updatePG and impl_transformsChanged on various nodes in the graph. I got this idea from this thread - https://forums.oracle.com/forums/thread.jspa?threadID=2242083
public class BorderPaneExample extends Application
{
private BorderPane root;
private StackPane centerPane;
#Override
public void start(Stage primaryStage) throws Exception
{
root = new BorderPane();
root.setTop(getMenu());
root.setBottom(getBottomVBox());
centerPane = getCenterPane();
root.setCenter(centerPane);
Scene scene = new Scene(root, 900, 500);
primaryStage.setTitle("BorderPane Example");
primaryStage.setScene(scene);
primaryStage.show();
}
private MenuBar getMenu()
{
MenuBar menuBar = new MenuBar();
MenuItem rightMenuItem = new MenuItem("Right");
rightMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
root.setRight(getRightHBox());
root.setBottom(null);
root.requestLayout();
}
});
MenuItem bottomMenuItem = new MenuItem("Bottom");
bottomMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
root.setRight(null);
root.setBottom(getBottomVBox());
}
});
Menu menu = new Menu("Move text");
menu.getItems().add(rightMenuItem);
menu.getItems().add(bottomMenuItem);
menuBar.getMenus().addAll(menu);
return menuBar;
}
private HBox getRightHBox()
{
HBox hbox = new HBox();
VBox vbox = new VBox(50);
vbox.setPadding(new Insets(0, 20, 0, 20));
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(new Text("Additional Info 1"),
new Text("Additional Info 2"), new Text("Additional Info 3"));
hbox.getChildren().addAll(new Separator(Orientation.VERTICAL), vbox);
return hbox;
}
private VBox getBottomVBox()
{
VBox vbox = new VBox();
HBox hbox = new HBox(20);
hbox.setPadding(new Insets(5));
hbox.setAlignment(Pos.CENTER);
hbox.getChildren().addAll(new Text("Footer Item 1")
, new Text("Footer Item 2"), new Text("Footer Item 3"));
vbox.getChildren().addAll(new Separator(), hbox);
return vbox;
}
private StackPane getCenterPane()
{
StackPane stackPane = new StackPane();
stackPane.setAlignment(Pos.CENTER);
final Rectangle rec = new Rectangle(200, 200);
rec.setFill(Color.DODGERBLUE);
rec.widthProperty().bind(stackPane.widthProperty().subtract(50));
rec.heightProperty().bind(stackPane.heightProperty().subtract(50));
stackPane.getChildren().addAll(rec);
return stackPane;
}
public static void main(String[] args)
{
Application.launch(args);
}
}
Any suggestions would be appreciated.
Thanks
For the sake of having an answer:
The StackPane needs to have its minimum size set in order to do clipping. So if you explicitly add stackPane.setMinSize(0, 0); to the getCenterPane() method, it should fix your problem.
So your getCenterPane() method would now look like this:
private StackPane getCenterPane()
{
StackPane stackPane = new StackPane();
stackPane.setMinSize(0, 0);
stackPane.setAlignment(Pos.CENTER);
final Rectangle rec = new Rectangle(200, 200);
rec.setFill(Color.DODGERBLUE);
rec.widthProperty().bind(stackPane.widthProperty().subtract(50));
rec.heightProperty().bind(stackPane.heightProperty().subtract(50));
stackPane.getChildren().addAll(rec);
return stackPane;
}