How to replicate this 2-1 layout in JavaFX? - java

I've looked into all of the layout options in the docs, and I am not allowed to use FXML. I don't understand where to start with configuring the 3 containers in the scene.

There are many ways you can do this; probably the most immediate is to put the two panes on the left in a VBox, and then use a BorderPane, with the VBox on the left and the "CCTV" pane in the center. This looks like:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class LayoutExample extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Pane lighting = new Pane();
lighting.getChildren().add(new Label("Lighting"));
Pane heating = new Pane();
heating.getChildren().add(new Label("Heating"));
Pane cctv = new Pane();
cctv.getChildren().add(new Label("CCTV"));
lighting.getStyleClass().add("control-pane");
heating.getStyleClass().add("control-pane");
cctv.getStyleClass().add("control-pane");
BorderPane root = new BorderPane() ;
VBox left = new VBox();
left.getChildren().add(lighting);
left.getChildren().add(heating);
// expand both panes in left to full width of vbox:
left.setFillWidth(true);
// add vertical space between panes:
left.setSpacing(5);
// allocate extra vertical space equally to both panes in left:
VBox.setVgrow(lighting, Priority.ALWAYS);
VBox.setVgrow(heating, Priority.ALWAYS);
root.setLeft(left);
root.setCenter(cctv);
// Add a left margin to the center pane to give it some space:
BorderPane.setMargin(cctv, new Insets(0, 0, 0, 10));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("layout-style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setWidth(800);
primaryStage.setHeight(640);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
This CSS isn't quite right, but gives you an idea how to add the borders:
.control-pane {
-fx-background-color: -fx-body-color, -fx-outer-border, -fx-body-color ;
-fx-background-insets: 0, 1, 2 ;
-fx-background-radius: 0, 1, 0 ;
-fx-padding: 3 ;
/** Just to demo empty boxes: **/
-fx-min-width: 300px ;
-fx-min-height: 300px ;
}
This looks like:
You could also use a HBox as the root, and set the hgrow on each to prioritize extra horizontal space on the CCTV pane. Or use a GridPane, and set the row span of the CCTV pane to 2. There are probably many other ways to do this.

Related

JavaFx : VBox still occupies space when invisible [duplicate]

Is it possible to shrink a GridPane row if the content of that row is both disabled and invisible?
When I set a Node to disable=true and visible=false, the cell still takes up space.
If I have 8 rows and only the first and last is visible I don't want the empty rows to take up much space. As if there was only two rows.
The only "solution" I could find was to set the size to zero. However I do not consider that a good solution. I would have to store the min/max size to set it back when/if the node becomes enabled/visible again.
Could perhaps CSS help with a better solution?
package com.company;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) {
launch(args);
}
/* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
*/
#Override
public void start(Stage stage) throws Exception {
Label label1 = new Label("Text");
Label label2 = new Label("Text");
Label label3 = new Label("Text");
label2.setDisable(true);
label2.setVisible(false);
GridPane root = new GridPane();
root.setGridLinesVisible(true);
root.add(label1, 0, 0);
GridPane.setVgrow(label1, Priority.NEVER);
root.add(label2, 0, 1);
GridPane.setVgrow(label2, Priority.NEVER);
root.add(label3, 0, 2);
GridPane.setVgrow(label3, Priority.NEVER);
stage.setScene(new Scene(root));
stage.setWidth(300);
stage.setHeight(300);
stage.setTitle("JavaFX 8 app");
stage.show();
}
}
If you do not want the parent to layout a node, you can set the managed property of the node to false.
Here is an image showing the difference in layout when I used the following line in your code:
label2.setManaged(false);

JavaFX split space evenly between two side panels in an HBox

I have an HBox that contains a square VBox in the center. The HBox width can be made larger than it's height, leaving extra space on the sides. I want to fill this extra space on the left and right with separate VBoxes where I will put buttons, info, etc. I want these two VBoxes, the "side panels," to always be of equal width. However, as you can see from the image below, when the right panel has a button and the left does not, it is wider than the left panel:
I thought
rightPanel.minWidthProperty().bindBidirectional(leftPanel.minWidthProperty());
rightPanel.prefWidthProperty().bindBidirectional(leftPanel.prefWidthProperty());
would do the trick, but it didn't.
Here's my code:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class FX010 extends Application{
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
GamePanel gp = new GamePanel();
Scene scene = new Scene(gp, 800, 600);
primaryStage.setTitle("testing");
primaryStage.minWidthProperty().bind(primaryStage.heightProperty());
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public class GamePanel extends HBox{
public GamePanel() {
this.setMinHeight(400);
final VBox boardBox = new VBox();
boardBox.alignmentProperty().set(Pos.CENTER);
this.alignmentProperty().set(Pos.CENTER);
VBox leftPanel, rightPanel;
leftPanel = new VBox();
rightPanel = new VBox();
leftPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.minWidthProperty().bindBidirectional(leftPanel.minWidthProperty());
rightPanel.prefWidthProperty().bindBidirectional(leftPanel.prefWidthProperty());
rightPanel.getChildren().add(new Button("testtesttest"));
HBox.setHgrow(leftPanel, Priority.ALWAYS);
HBox.setHgrow(rightPanel, Priority.ALWAYS);
StackPane board = new StackPane(new Rectangle(100,100,Color.RED));
board.setBorder(new Border(new BorderStroke(Color.DARKBLUE, BorderStrokeStyle.DASHED,
CornerRadii.EMPTY,new BorderWidths(1))));
final NumberBinding binding = Bindings.min(widthProperty(), heightProperty());
boardBox.prefWidthProperty().bind(binding);
boardBox.prefHeightProperty().bind(binding);
boardBox.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
VBox.setVgrow(board, Priority.ALWAYS);
boardBox.getChildren().add(board);
getChildren().addAll(leftPanel, boardBox, rightPanel);
//HBox.setHgrow(this, Priority.ALWAYS);
}
}
}
How can I force leftPanel to always have the same width as rightPanel, while still ensuring that boardBox is always a square?
Thanks!
It works when you add e. g.:
leftPanel.setPrefWidth(100d);
rightPanel.setPrefWidth(100d);
Edit: Maybe it would be better if you use a GridPane as a root layout where you can have three columns with a fixed percentage width like e. g.: 15 % (left-hand side), 70 % (center) and 15 % (right-hand side). But only you can know and decide what fits best for your project. :-P
After a lot of testing, I got this to work:
public class GamePanel extends HBox{
Pane leftPanel, rightPanel, iLeft, iRight;
VBox boardBox;
public GamePanel() {
this.setMinHeight(400);
iLeft = new Pane();
boardBox = new VBox();
iRight = new Pane();
boardBox.alignmentProperty().set(Pos.CENTER);
this.alignmentProperty().set(Pos.CENTER);
leftPanel = new Pane();
rightPanel = new Pane();
leftPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setPrefWidth(0);
leftPanel.setPrefWidth(0);
iRight.getChildren().add(new Button("testtesttest"));
rightPanel.getChildren().add(iRight);
HBox.setHgrow(leftPanel, Priority.ALWAYS);
HBox.setHgrow(rightPanel, Priority.ALWAYS);
StackPane board = new StackPane(new Rectangle(100,100,Color.RED));
board.setBorder(new Border(new BorderStroke(Color.DARKBLUE, BorderStrokeStyle.DASHED,
CornerRadii.EMPTY,new BorderWidths(1))));
final NumberBinding binding = Bindings.min(widthProperty(), heightProperty());
boardBox.prefWidthProperty().bind(binding);
boardBox.prefHeightProperty().bind(binding);
boardBox.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
VBox.setVgrow(board, Priority.ALWAYS);
boardBox.getChildren().add(board);
getChildren().addAll(leftPanel, boardBox, rightPanel);
//HBox.setHgrow(this, Priority.ALWAYS);
}
}
This solution involves setting the left and right panel's prefWidth to zero, then adding internal panes into each panel, which the content is then added to. I think the reason that this works is because space is allocated for the prefWidth before the panel's size is expanded by the Hgrow constraint. Since equal amounts of space are added to each panel by the HBox, the panel with a greater prefWidth ends up bigger. By setting both to zero, they both start with no prefWidth and thus end up at the same size. I believe that's also why anko's answer seemed to work - because when they start with equal prefWidths and the same amount of space is added to each, they end up with the same size. However, setting a prefWidth of 100 messes with the boardBox's size (makes it not a square) when the stage's width is shrunk as small as possible.
I'm sure there is a better way to do this, and I'd be happy to accept a better answer.

GridPane doesn't align in center

I am making a Login Screen with a number pad, and I can't seem to center align a GridPane of buttons in a Pane. What am I doing wrong?
Main.java
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.input.KeyCombination;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args){
launch(args);
}
public void start(Stage primaryStage) throws Exception{
Rectangle2D bounds = Screen.getPrimary().getBounds();
LoginScreen loginScreen = new LoginScreen(bounds.getWidth(), bounds.getHeight());
Scene scene = new Scene(loginScreen.get());
primaryStage.setScene(scene);
primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
primaryStage.show();
primaryStage.setFullScreen(true);
}
}
LoginScreen.java
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
public class LoginScreen {
private Pane root;
private GridPane numberPad;
public LoginScreen(double screenWidth, double screenHeight){
root = new Pane();
root.setPrefSize(screenWidth, screenHeight);
root.setBackground(new Background(new BackgroundFill(Color.AQUA, CornerRadii.EMPTY, Insets.EMPTY)));
numberPad = new GridPane();
Button button01 = new Button("1");
Button button02 = new Button("2");
Button button03 = new Button("3");
Button button04 = new Button("4");
Button button05 = new Button("5");
Button button06 = new Button("6");
Button button07 = new Button("7");
Button button08 = new Button("8");
Button button09 = new Button("9");
numberPad.setAlignment(Pos.CENTER);
numberPad.add(button01, 0, 0);
numberPad.add(button02, 1, 0);
numberPad.add(button03, 2, 0);
numberPad.add(button04, 0, 1);
numberPad.add(button05, 1, 1);
numberPad.add(button06, 2, 1);
numberPad.add(button07, 0, 2);
numberPad.add(button08, 1, 2);
numberPad.add(button09, 2, 2);
root.getChildren().addAll(numberPad);
}
public Pane get(){
return root;
}
}
GUI code is verbose, and this post editor isn't letting me post my question as is, so I need these extra lines to get it to accept my question. If I thought I could cut down my code to just the numberPad.setAlignment(Pos.Center) and still make it clear how I am attempting to center my GridPane I most certainly would. I do humbly thank those who might lend me their time to help me solve this issue I have.
Edit 01:
My issue is that the GridPane itself is drawn in the top left corner of the screen rather than in the center of the screen.
You need to actually set the alignment for the parent container. A Pane is not a valid container for doing this, however.
If you were to use a VBox instead, you could simply set its alignment as so:
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
That will cause all of the children of the VBox to be placed in the center.
The Pos enum also provides other methods of positioning, including TOP_CENTER, TOP_LEFT, and BOTTOM_RIGHT, for example.

JavaFx 8 - A class that has a border than you're able to color and able to have text in the middle of it

Does anyone know of a class that i can use that is essential a rectangle, BUT it has text in the middle of the rectangle and the rectangle has a fill color along with a border color(the border can be changed to red or something along those lines)
Essentially right now i have a pane, and i want to make a 2D grid(10x10), where each individual object in the grid is a rectangle-typed object that has a number text center justified, a fill color, and a border color.
Note: I've tried to use gridpane, but the lack of documentation that i've found has led me to believe i can only set the fill color, and each cell in the grid pane does NOT look like a separate object like i want it to. I've also tried to implement rectangle but the rectangle doesn't have text or a border that i can manipulate.
Thank you for your help.
Just use a Label. Here's a proof of concept:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class CustomLabelDemo extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Hello World");
label.setStyle(
"-fx-alignment: center;"
+"-fx-padding: 6px;"
+"-fx-background-color: red, -fx-background;"
+"-fx-background-insets: 0, 4px;"
);
StackPane root = new StackPane(label);
primaryStage.setScene(new Scene(root, 350, 75));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The way the css is working here is that it defines two backgrounds: the first (and thus the one at the back) is red; the one in front is set to -fx-background, which is the color defined in the default stylesheet for the background of most controls. Corresponding to these are two insets for the two backgrounds: the first set to zero, and the second set to 4 pixels. This means that 4 pixels of the red border will be visible. The padding is just set to make sure the text doesn't overlap the outer background (the border).
In a real application, you should put the style in an external file. You can also define a "looked-up-color" for the border color; this will make it much easier to change the color at runtime:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CustomLabelDemo extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Hello World");
label.getStyleClass().add("custom-label");
Button changeColorButton = new Button("Change to green");
changeColorButton.setOnAction(event -> label.setStyle("custom-label-border-color: green;"));
VBox root = new VBox(10, label, changeColorButton);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 350, 75);
scene.getStylesheets().add("custom-label.css");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with custom-label.css:
.custom-label {
custom-label-border-color: red ;
-fx-alignment: center;
-fx-padding: 6px;
-fx-background-color: custom-label-border-color, -fx-background;
-fx-background-insets: 0, 4px;
}
.button {
-fx-alignment: center ;
}
If you have a fixed set of states that the colors represent, you might want to use a pseudoclass to represent the state:
import javafx.application.Application;
import javafx.css.PseudoClass;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CustomLabelDemo extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Hello World");
label.getStyleClass().add("custom-label");
CheckBox errorCheckBox = new CheckBox("Error");
PseudoClass errorState = PseudoClass.getPseudoClass("error");
errorCheckBox.selectedProperty().addListener((obs, wasSelected, isNowSelected) ->
label.pseudoClassStateChanged(errorState, isNowSelected));
VBox root = new VBox(10, label, errorCheckBox);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 350, 75);
scene.getStylesheets().add("custom-label.css");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
custom-label.css:
.custom-label {
custom-label-border-color: green ;
-fx-alignment: center;
-fx-padding: 6px;
-fx-background-color: custom-label-border-color, -fx-background;
-fx-background-insets: 0, 4px;
}
.custom-label:error {
custom-label-border-color: red ;
}
.check-box {
-fx-alignment: center ;
}
I think your best bet is to make a custom control, exposing the properties you need.
See http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm for info and examples.

How to create tabs with icons in JavaFX

I want to create tabs panel with icons similar to the Firefox configuration panel with JavaFX:
Is there any example which I can use to see how to implement this?
Tabs, like many other elements in JavaFX, have a method called setGraphic(Node value), in which you can put any JavaFX node. Example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class TabPaneTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setGraphic(new Circle(0, 0, 10));
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Result:
I know its an old thread, but i didnt find a direct answer anywhere. So i thought of posting it some that it will be helpfull for some searching for it.
This is what i did to get a tab like firefox preferences screen.
Add the image to the tab with setGraphics and add the following code to the application css file. My image size was 48x48. So i went for height as 70.
.tab-label {
-fx-content-display: top;
}
.tab-pane {
-fx-tab-min-height: 70;
-fx-tab-max-height: 70;
}
How to add image directly from image url:
Tab tab = new Tab();
tab.setGraphic(buildImage("patch/to/image");
// Helper method to create image from image patch
private static ImageView buildImage(String imgPatch) {
Image i = new Image(imgPatch);
ImageView imageView = new ImageView();
//You can set width and height
imageView.setFitHeight(16);
imageView.setFitWidth(16);
imageView.setImage(i);
return imageView;
}

Categories