I have a JavaFX table with pagination control on which I applied padding.
pagination.setPadding(new Insets(5, 5, 0, 5));
I added padding, but in this case the pagination control and table are very close to each other. How I can add some space between them?
I just tried and it's odd that this doesn't work. A quick solution / workaround is to put both the TableView and the Pagination into a VBox and add spacing.
Like this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
TableView tv = new TableView();
Pagination pg = new Pagination();
VBox root = new VBox();
root.setSpacing(10);
root.getChildren().addAll( tv, pg);
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Related
I am trying to build a dummy webshop with JavaFX. I deliberately do not use fxml, scenebuilder, maven or any other build tool. Just plain JavaFX, in order to really get to understand the basics.
However, I ran into a problem creating and navigating different 'pages'.
I have tried various creative solutions, like this one (is posting links allowed?), but none fully work for me, as I want every 'page', 'view' or scene in a seperate java class file, in order to keep everything structured and orderly.
I figured I'd make a Borderpane as a parent layout for every page
abstract class WindowBase extends BorderPane {
public abstract BorderPane render(App app);
public WindowBase() {
Label labelTop = new Label("Top box");
HBox topBox = new HBox();
topBox.setStyle("-fx-background-color: red;");
topBox.getChildren().addAll(labelTop);
Label labelLeft = new Label("Left box");
VBox leftBox = new VBox();
leftBox.setStyle("-fx-background-color: green;");
leftBox.getChildren().addAll(labelLeft);
Label labelRight = new Label("Right box");
VBox rightBox = new VBox();
rightBox.setStyle("-fx-background-color: blue;");
rightBox.getChildren().addAll(labelRight);
Label labelBottom = new Label("Bottom box");
HBox bottomBox = new HBox();
bottomBox.setStyle("-fx-background-color: yellow;");
bottomBox.getChildren().addAll(labelBottom);
this.setTop(topBox);
this.setLeft(leftBox);
this.setRight(rightBox);
this.setBottom(bottomBox);
}
}
and a child, the home page
public class Homepage extends WindowBase {
public BorderPane render(App app) {
Button button = new Button("Go to shopping cart");
button.setOnAction((event) -> app.toShoppingCart());
StackPane centerPane = new StackPane();
centerPane.getChildren().add(button);
this.setCenter(centerPane);
return this;
}
}
and lastly my App.java that runs everything
public class App extends Application{
private WindowBase view;
public void start(Stage stage) throws Exception {
view = new Homepage();
stage.setScene(new Scene(view.render(this)));
stage.setFullScreen(true);
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
public void toHomepage() {
this.view = new Homepage();
}
public void toShoppingCart() {
this.view = new ShoppingCart();
}
}
I understand that I can't pass this (App) as an argument to view.render(), use the parameter within the method render and expect to be able to manipulate it, because it only creates a new instance of App as soon as it gets there. However, I see no other way either.
I tried placing the navigation buttons in the App class, in order to be able to manipulate view, but then I cannot call on the buttons from the subsequent views.
There must be a way to achieve what I want without writing the complete GUI in one file, right? Should I make my view static in stead, is that it?
Instead of BorderPanes I am of course also okay with using Scenes, whatever works.
I have figured out exactly the solution that I wanted. Posting it here for whoever encounters the same situation.
Class WindowBase
public class WindowBase {
public BorderPane getMainPane() {
Label labelTop = new Label("Top box");
HBox topBox = new HBox();
topBox.setStyle("-fx-background-color: red;");
topBox.getChildren().addAll(labelTop);
Label labelLeft = new Label("Left box");
VBox leftBox = new VBox();
leftBox.setStyle("-fx-background-color: green;");
leftBox.getChildren().addAll(labelLeft);
Label labelRight = new Label("Right box");
VBox rightBox = new VBox();
rightBox.setStyle("-fx-background-color: blue;");
rightBox.getChildren().addAll(labelRight);
Label labelBottom = new Label("Bottom box");
HBox bottomBox = new HBox();
bottomBox.setStyle("-fx-background-color: yellow;");
bottomBox.getChildren().addAll(labelBottom);
BorderPane borderPane = new BorderPane();
borderPane.setTop(topBox);
borderPane.setLeft(leftBox);
borderPane.setRight(rightBox);
borderPane.setBottom(bottomBox);
return borderPane;
}
}
Class Homepage
public class Homepage extends WindowBase {
public BorderPane render(Button toShoppingCart) {
Label label = new Label("This is the homepage.");
label.setStyle(
"-fx-font: normal bold 30px 'elephant'; -fx-text-fill: black; -fx-background-color: red;");
StackPane stackPane = new StackPane();
stackPane.getChildren().addAll(label);
BorderPane mainPane = getMainPane();
VBox leftBox = (VBox) mainPane.getLeft();
leftBox.getChildren().add(toShoppingCart);
//I do not understand why this works. I abstracted leftBox from mainPane, then added shoppingCart, but never added the abstracted
// leftBox back to the mainPane before returning it. This should not work, but it does. leftBox.getChildren().add(toShoppingCart)
// should have no effect.
//However, mainPane.getChildren().add(leftBox) throws an IllegalArgumentException about duplicate components, which is to be
// expected if the leftBox is already automatically added back to the mainPane.
mainPane.setCenter(stackPane);
return mainPane;
}
}
Class ShoppingCart
public class ShoppingCart extends WindowBase {
public ShoppingCart() {
super();
}
public BorderPane render(Button toHomepage) {
Label label = new Label("This is the shopping cart.");
label.setStyle(
"-fx-font: normal bold 30px 'elephant'; -fx-text-fill: black; -fx-background-color: red;");
StackPane centerPane = new StackPane();
centerPane.getChildren().add(label);
BorderPane mainPane = getMainPane();
VBox leftBox = (VBox) mainPane.getLeft();
leftBox.getChildren().add(toHomepage);
mainPane.setCenter(centerPane);
return mainPane;
}
}
Class App
public class App extends Application{
Scene scene;
#Override
public void start(Stage stage) throws Exception {
Homepage homePane = new Homepage();
Button toHomepage = new Button("Back to home page");
ShoppingCart shoppingPane = new ShoppingCart();
Button toShoppingCart = new Button("To shopping cart");
toHomepage.setOnAction(e -> scene.setRoot(homePane.render(toShoppingCart)));
toShoppingCart.setOnAction(e -> scene.setRoot(shoppingPane.render(toHomepage)));
scene = new Scene(homePane.render(toShoppingCart), 600, 400);
stage.setScene(scene);
stage.setFullScreen(true);
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
I have managed to place a Button inside a TitledPane using setGraphic but I want it to be located on the right side; here is the code:
#Override
public void start(Stage primaryStage) {
Accordion acordion = new Accordion();
TitledPane tp1 = new TitledPane();
Button b1 = new Button();
b1.setText("X");
tp1.setGraphic(b1);
acordion.getPanes().addAll(tp1);
Scene scene = new Scene(acordion, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
The Button should be located on the right but I do not know how to do it
Set the alignment property of TitledPane to CENTER_RIGHT:
tp1.setAlignment(Pos.CENTER_RIGHT);
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.
Does exists a Java FX component like one that appears from top and goes down, as in the gif below?
I was able to implement a demo based on transition of pane. It looks like:
The weakness of this approach is it doesn't work with a Window which has standard border, buttons, etc. A developer is responsible to build a nice window based on a Pane.
The other problem is resizing of the parent window will resize the sub pane as well. But if you have not resizable parent dialog it should not be a problem.
You are welcome to copy-paste this code and play with it:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
final SubPane subPane = new SubPane();
final TranslateTransition dialogAnimator =
new TranslateTransition(new Duration(500), subPane);
final Button showSubPaneButton = new Button("Slide a sub pane");
showSubPaneButton.setOnAction(event -> {
dialogAnimator.setToY(10);
dialogAnimator.play();
});
subPane.setCloseAction(event -> {
dialogAnimator.setToY(-subPane.getHeight());
dialogAnimator.play();
});
final Pane rootPane = new StackPane(showSubPaneButton, subPane);
rootPane.setPrefWidth(400);
rootPane.setPrefHeight(300);
// By default hide the given pane by moving to the top.
Platform.runLater(() -> subPane.setTranslateY(-subPane.getHeight()));
primaryStage.setTitle("Drop slided dialog");
primaryStage.setScene(new Scene(rootPane));
primaryStage.show();
}
}
class SubPane extends BorderPane {
private final Button dialogButton = new Button("Close");
SubPane() {
final Pane centralPane = new StackPane(dialogButton);
centralPane.setStyle(
"-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);-fx-padding: 10;" +
"-fx-background-color: firebrick;-fx-background-radius: 10;");
setCenter(centralPane);
final Pane blankLeftPane = new StackPane();
blankLeftPane.setPrefWidth(100);
setLeft(blankLeftPane);
final Pane blankRightPane = new StackPane();
blankRightPane.setPrefWidth(100);
setRight(blankRightPane);
final Pane blankBottomPane = new StackPane();
blankBottomPane.setPrefHeight(200);
setBottom(blankBottomPane);
}
void setCloseAction(final EventHandler<ActionEvent> closeCallback) {
dialogButton.setOnAction(closeCallback);
}
}
If you're talking about the dialog window, ControlsFX have something similar NotificationPane.
My button is located under the rectangle. It is currently like in the picture on the left. I want to pad the button like in the picture on the right.
How can I do that? Thanks for reading.
Here's my code.
public class Rect extends Application {
private Button btn1 = new Button("Rotate");
private Rectangle r1 = new Rectangle(50, 100);
#Override
public void start(Stage primaryStage) throws Exception {
GridPane gridPane = new GridPane();
r1.setStroke(Color.BLACK);
r1.setFill(Color.WHITE);
gridPane.add(r1, 0, 0);
gridPane.add(btn1, 0, 1);
gridPane.setAlignment(Pos.CENTER);
btn1.setAlignment(Pos.BOTTOM_CENTER);
Scene scene = new Scene(gridPane,200,200);
primaryStage.setTitle("RotateRectangleFX");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
At the moment you are doing this:
gridPane.setAlignment(Pos.CENTER);
btn1.setAlignment(Pos.BOTTOM_CENTER);
You should be setting the alignment of r1 instead like follows:
r1.setAlignment(Pos.CENTER);
btn1.setAlignment(Pos.BOTTOM_CENTER);