I have a SplitPane (verticle) at the Center of a BorderPane in my Gui. In my SplitPane I add an HBox as the top and a FlowPane as the bottom. Everytime I add a set of cards to a VBox and add the VBox to my FlowPane it adds the VBoxes one after the other instead of adding them vertically. Does anyone know why?
#FXML
private FlowPane setsArea;
//sets
public void addSet(CardSet set) {
VBox setView = new VBox(20);
for (Card card : set.getCards()) {
ImageView imageView = new ImageView(card.getImgUrl());
setView.getChildren().add(imageView);
}
setsArea.getChildren().add(setView);
setViews.put(set, setView);
}
My GameView.fxml where I am adding the SplitPane as the center of my BorderPane.
<center>
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" style="-fx-background-image: url('game.jpg');" BorderPane.alignment="CENTER">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<HBox fx:id="playAreaTop" />
</children></AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<FlowPane fx:id="setsArea" />
</children></AnchorPane>
</items>
</SplitPane>
</center>
How I am adding the cardSets:
Card card = new Basic(Suit.CLUBS, 4, 1);
Card card2 = new Basic(Suit.HEARTS, 5, 2);
Card card3 = new Joker(Suit.JOKER, 15, 3);
Card card4 = new Ace(Suit.HEARTS, 14, 4);
ArrayList<Card> cards = new ArrayList<>();
cards.add(card);
cards.add(card2);
cards.add(card4);
CardSet cardSet = new CardSet(cards);
gameView.addSet(cardSet);
gameView.addSet(cardSet);
gameView.addSet(cardSet);
gameView.addSet(cardSet);
gameView.addSet(cardSet);
gameView.addSet(cardSet);
Thanks.
Adding image into VBox and put them all in a FlowPane don't make them vertically stacked you should replace your FlowPane into a VBox and add the ImageViews to the VBox which stack it's item vertically like so:
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" style="-fx-background-image: url('game.jpg');" BorderPane.alignment="CENTER">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<HBox fx:id="playAreaTop" />
</children></AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<VBox fx:id="setsArea" />
</children></AnchorPane>
</items>
#FXML
private VBox setsArea;
public void addSet(CardSet set){
for (Card card : set.getCards()) {
ImageView imageView = new ImageView(card.getImgUrl());
setsArea.getChildren().add(imageView);
}
setViews.put(set, setView);
}
Related
I have a FlowPane wrapped in a ScrollPane. FlowPane orientation is Vertical, so it will wrap the controls. But I want to set the FlowPane to resize vertically if the columns size is greater than the width of ScrollPane. I've tried a lot of settings, both on ScrollPane and FlowPane but none of them helped me with my wish.
As an image of how I want to do is something like this:
(red contur is ScrollPane, green is FlowPane)
Containers, after the flow pane is populated, with ScrollPane's width more than two columns of controls:
How it works right now, after resizing:
How I want to do after resizing the ScrollPane:
Can this be achieved? What settings I must do to both ScrollPane and FlowPane?
Edit:
Minimal reproduction code:
hello-view.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="424.0" prefWidth="457.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demo.HelloController">
<children>
<AnchorPane layoutX="14.0" layoutY="14.0" prefHeight="399.0" prefWidth="430.0" style="-fx-border-color: #555555;" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<children>
<ScrollPane fitToHeight="true" fitToWidth="true" focusTraversable="false" hbarPolicy="NEVER" layoutX="14.0" layoutY="13.0" maxWidth="1.7976931348623157E308" prefHeight="377.0" prefWidth="404.0" style="-fx-border-color: red; -fx-border-width: 2;" AnchorPane.bottomAnchor="7.0" AnchorPane.leftAnchor="13.0" AnchorPane.rightAnchor="12.0" AnchorPane.topAnchor="12.0">
<content>
<FlowPane maxWidth="1.7976931348623157E308" orientation="VERTICAL" prefHeight="363.0" prefWidth="397.0" rowValignment="TOP" style="-fx-border-color: green; -fx-border-width: 2;">
<children>
<Button mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="1">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="12.0" layoutY="12.0" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="2">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="10.0" layoutY="135.0" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="3">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="154.0" layoutY="10.0" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="4">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
</children>
</FlowPane>
</content>
</ScrollPane>
</children>
</AnchorPane>
</children>
</AnchorPane>
HelloController.java:
package com.example.demo;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
#FXML
private Label welcomeText;
#FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
}
HelloApplication.java
package com.example.demo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
HelloApplication.java and HelloController.java are default demo files from starting project in JavaFX.
Conclusion:
Is there a combination of properties for ScrollPane and FlowPane to be able to resize the FlowPane vertically and stop resizing in the right when the control inside tries to move to create a new column (this happens when ScrollPane resize vertically)? I don't want to create those invisible columns in the right, instead grows the FlowPane vertically!
Mention: this could happens in two way
when resize form from the bottom, and the controls from the bottom of the FlowPane will move to the top, and the FlowPane will resize automatically to the right and put the controls in the hidden area of FlowPane, (and)
When you resize form horizontally and there is no more space to move the controls from the right column to the next row, so the FlowPane will not stay anchored to right and to try to create an "invisible" row (or as many as it takes to move needed controls down).
I hope I make it clear as possible.
This answer I found it myself and it works only for FlowPane containing controls with the same size.
Purpose:
Allow user to populate a FlowPane in Vertical orientation, with parent ScrollPane's scrollbars set only to vertical scrollbar visible (when needed) and the FlowPane width to fit ScrollPane's width always.
Starting from a demo project in JavaFX, this is the fxml file which contains definition for the main-view (hello-view.fxml in this case).
hello-view.fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="424.0" prefWidth="457.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demo.HelloController">
<children>
<AnchorPane layoutX="14.0" layoutY="14.0" prefHeight="399.0" prefWidth="430.0" style="-fx-border-color: #555555;" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<children>
<ScrollPane fx:id="scrollPane" fitToWidth="true" focusTraversable="false" hbarPolicy="NEVER" layoutX="14.0" layoutY="13.0" maxHeight="1.7976931348623157E308" maxWidth="-Infinity" prefHeight="377.0" prefWidth="404.0" style="-fx-border-color: red; -fx-border-width: 0;" AnchorPane.bottomAnchor="7.0" AnchorPane.leftAnchor="13.0" AnchorPane.rightAnchor="12.0" AnchorPane.topAnchor="12.0">
<content>
<AnchorPane fx:id="ancFlow">
<children>
<FlowPane fx:id="flowPane" orientation="VERTICAL" prefHeight="368.0" prefWidth="396.0" prefWrapLength="10.0" rowValignment="TOP" style="-fx-border-color: green; -fx-border-width: 0;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="1">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="12.0" layoutY="12.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="2">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="10.0" layoutY="135.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="3">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
<Button layoutX="154.0" layoutY="10.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="121.0" prefWidth="140.0" text="4">
<FlowPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</FlowPane.margin>
<font>
<Font name="System Bold" size="24.0" />
</font>
</Button>
</children>
</FlowPane>
</children>
</AnchorPane>
</content>
</ScrollPane>
</children>
</AnchorPane>
</children>
</AnchorPane>
HelloController.java file:
package com.example.demo;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import java.net.URL;
import java.util.ResourceBundle;
public class HelloController implements Initializable {
private final long buttonWidth = 144;
private final long buttonHeight = 125;
private double columns;
private double rows;
#FXML
private AnchorPane ancFlow;
#FXML
private ScrollPane scrollPane;
#FXML
private FlowPane flowPane;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// next line was used to see how ancPane is resizing
//ancFlow.setBackground(new Background(new BackgroundFill(Color.rgb(220, 120, 120), new CornerRadii(0), new Insets(0))));
}
public void resizeFlowPaneParent(){
scrollPane.heightProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
if(scrollPane.getHeight() < buttonHeight) return;
double verticalPadding = scrollPane.getPadding().getTop() + scrollPane.getPadding().getTop();
ancFlow.setPrefWidth(scrollPane.getWidth() - (scrollPane.getWidth() - scrollPane.getViewportBounds().getWidth()));
int controls = flowPane.getChildren().size();
rows = Math.floorDiv(newValue.longValue() , buttonHeight + (long)verticalPadding);
if((long)rows == 0) return;
columns = Math.ceilDiv(controls, (long)(rows));
double matchColumns = Math.floorDiv((long)(scrollPane.getWidth()- (scrollPane.getWidth() - scrollPane.getViewportBounds().getWidth())), buttonWidth);
if (columns <= matchColumns) {
if(rows * buttonHeight - (long)verticalPadding <= scrollPane.getHeight() - verticalPadding || (rows * columns * buttonHeight ) > controls * buttonHeight )
{
ancFlow.setPrefHeight(scrollPane.getHeight()-verticalPadding);
}
else
{
ancFlow.setPrefHeight(rows * buttonHeight);
}
}
else
{
double matchRows = Math.ceilDiv(controls, (long)matchColumns);
ancFlow.setPrefHeight(matchRows * buttonHeight);
}
}
});
scrollPane.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
if(newValue.longValue() - (newValue.longValue() - scrollPane.getViewportBounds().getWidth()) < buttonWidth) return;
double verticalPadding = scrollPane.getPadding().getTop() + scrollPane.getPadding().getTop();
ancFlow.setPrefWidth(newValue.longValue() - (newValue.longValue() - scrollPane.getViewportBounds().getWidth()));
int controls = flowPane.getChildren().size();
columns = Math.floorDiv(newValue.longValue() - (long)(newValue.longValue() - scrollPane.getViewportBounds().getWidth()), buttonWidth);
rows = Math.ceilDiv(controls, (long)columns);
if(rows * buttonHeight < scrollPane.getHeight())
{
ancFlow.setPrefHeight(scrollPane.getHeight()-verticalPadding);
}
else
{
ancFlow.setPrefHeight(rows * buttonHeight);
}
}
});
}
}
HelloApplication.java file:
package com.example.demo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
((HelloController)fxmlLoader.getController()).resizeFlowPaneParent();
stage.setWidth(stage.getWidth() + 1);
stage.setHeight(stage.getHeight() + 1);
}
public static void main(String[] args) {
launch();
}
}
The approach was to wrap the FlowPane in a AnchorPane. FlowPane is anchored in AnchorPane to all bounds. The AnchorPane is wrapped in ScrollPane.
In controller I've created a public method in which I added listners to widthProperty() and heightProperty() of ScrollPane to be able to calculate the rows needed for resizing the AnchorPane, based on how many items are in FlowPane and how many columns could be made with the ScrollPane's width. This method was added because size of controls must be read after the scene is displayed, which I've done it in HelloApplication.java main class. In this way listners are added after all items are displayed, and it will be calculated correctly.
Demo:
I want my Chat Window to be reziable and scrollable, so far everything works except the ChatLog itself.
I need a scroll bar, that's why I put the VBox inside of a ScrollPane (which is child of an AnchorPane), but this way only the ScrollPane is responsive (thanks to Anchor Values). If I unwrap VBox I can set Anchor Values, then it works but I'm loosing my scroll bar.
How can I mantain the scroll bar for ChatLog AND make it responsive (attached on the right side)?
FXML:
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #5b2529;" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
<children>
<ScrollPane fx:id="scrollPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="265.0" prefWidth="592.0" AnchorPane.bottomAnchor="57.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
<content>
<VBox fx:id="chatLog" prefHeight="265.0" prefWidth="575.0" />
</content></ScrollPane>
<TextArea fx:id="messageBox" layoutX="5.0" layoutY="349.0" onKeyPressed="#onEnterSend" prefHeight="47.0" prefWidth="536.0" promptText="enter message..." AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="61.0" />
<Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" onMouseClicked="#setSendButtonAction" prefHeight="47.0" prefWidth="52.0" text="Send" AnchorPane.bottomAnchor="5.0" AnchorPane.rightAnchor="5.0" />
</children>
</AnchorPane>
public void addLabel(String message, Pos position) {
HBox hBox = new HBox();
hBox.setAlignment(position);
hBox.setPadding(new Insets(5, 5, 5, 10));
Text text = new Text(message);
TextFlow textFlow = new TextFlow(text);
textFlow.setStyle("-fx-background-color: rgb(233,233,235);" +
"-fx-background-radius: 20px");
textFlow.setPadding(new Insets(5, 10, 5, 10));
hBox.getChildren().add(textFlow);
Platform.runLater(new Runnable() {
#Override
public void run() {
chatLog.getChildren().add(hBox);
}
});
}
public void setSendButtonAction() {
String message = messageBox.getText().replaceAll("[\n\r]", "");
try {
if (!message.isEmpty()) {
// show message on the sending client window
addLabel(message, Pos.CENTER_RIGHT);
}
}
To answer your actual question, below is what you need add to the ScrollPane (in fxml with your current layout).
fitToHeight="true" fitToWidth="true"
The above code will make your VBox responsive with the ScrollPane.
I also suggest to change your layout to get rid of AnchorPane (will all those hardcoded positions). You can use VBox/HBox in conjuction with vgrow/hgrow policies. The optimized fxml will be as below:
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<VBox style="-fx-background-color: #5b2529;" spacing="5" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.lmu.jungejunkervp.ClientWindowController">
<children>
<ScrollPane fx:id="scrollPane" prefHeight="265.0" prefWidth="592.0" fitToHeight="true" fitToWidth="true" VBox.vgrow="ALWAYS">
<content>
<VBox fx:id="chatLog"/>
</content>
</ScrollPane>
<HBox spacing="5">
<TextArea fx:id="messageBox" onKeyPressed="#onEnterSend" prefHeight="47.0" promptText="enter message..." HBox.hgrow="ALWAYS" />
<Button fx:id="sendButton" mnemonicParsing="false" onAction="#setSendButtonAction" prefHeight="47.0" minWidth="52.0" text="Send"/>
</HBox>
</children>
<padding>
<Insets topRightBottomLeft="5"/>
</padding>
</VBox>
Having said that, I think you need to consider changing your layout to what #jewelsea mentioned in the provided example (using ListView).
i will try to expose my problem as good as i can.
This is the XML
<VBox fx:id="main" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="500.0" prefWidth="800.0" style="-fx-background-color: #DEE2E6;" xmlns="http://javafx.com/javafx/17"
xmlns:fx="http://javafx.com/fxml/1">
<BorderPane prefHeight="408.0" prefWidth="600.0" VBox.vgrow="ALWAYS">
<left>
<AnchorPane fx:id="section_to_hide" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" BorderPane.alignment="CENTER">
<Label fx:id="hide_btn1" layoutX="14.0" layoutY="54.0" onMouseClicked="#hide" text="Hide me">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</AnchorPane>
</left>
<center>
<BorderPane fx:id="main_content" prefHeight="442.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<left>
<VBox fx:id="side_section_mails" prefHeight="500.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<AnchorPane prefHeight="59.0" prefWidth="200.0">
<Label fx:id="hide_btn" layoutX="14.0" layoutY="19.0" onMouseClicked="#hide" text="< Hide it">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</AnchorPane>
</VBox>
</left>
<center>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #CED4DA;" BorderPane.alignment="CENTER"/>
</center>
</BorderPane>
</center>
</BorderPane>
</VBox>
Controller:
public class Controller {
#FXML
private Label hide_btn;
#FXML
private AnchorPane section_to_hide;
#FXML
private void hide() {
Animation animation = new Timeline(
new KeyFrame(Duration.millis(300),
new KeyValue(section_to_hide.prefWidthProperty(), 0),
new KeyValue(section_to_hide.minWidthProperty(), 0)
)
);
animation.play();
}
#FXML
public void initialize() { }
}
The problem is: i want the content of the AnchorPane (section_to_hide) to collapse with its parent. Because this is what happens:
https://gyazo.com/41dfc5340a8e4495938cbc43d801fea2
It seems that the label inside the AnchorPane (section_to_hide) does not collapse with the parent.
Is there a way to make it work?
+1 for #Oboe answer. I would like add a bit more to his answer.
If you set managed/visible to false after the animation is finished, you may not see a smooth transition of the label. Means the complete Label is still visible while the pane closes (as in below gif) and gets invisible only after the animation is finished.
On the other hand, if you bind the clip with the bounds of the section that is hiding, you will get an effect of hiding something with a piece of cover (as in below gif) but not like hiding by sliding the section.
If the above behaviour is Ok for you, then no issues :). But if your are looking for a peferct sliding animation (as in below gif), you need to add another change of translating the clip position also.
But for this, you will need to wrap the hiding pane with an extra container.
The end implementation will be :
Outer container width is reduced to 0
Hiding container is translated in negative direction
And the clip is translated in positive direction.
Wrap section_to_hide with StackPane in fxml:
<StackPane fx:id="section_to_hide_container" prefHeight="200.0" prefWidth="200.0" alignment="CENTER_LEFT">
<AnchorPane fx:id="section_to_hide" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" >
<children>
<Label fx:id="hide_btn1" layoutX="14.0" layoutY="54.0" onMouseClicked="#hide"
text="Hide me">
<font>
<Font name="Prompt-Black" size="24.0"/>
</font>
</Label>
</children>
</AnchorPane>
</StackPane>
And you controller code will change as below:
#FXML
private StackPane section_to_hide_container;
#FXML
private void hide() {
double width = section_to_hide_container.getWidth();
// Create a clip and apply on the pane to hide
Rectangle clip = new Rectangle();
clip.setWidth(width);
clip.heightProperty().bind(section_to_hide.heightProperty());
section_to_hide.setClip(clip);
Animation animation = new Timeline(
new KeyFrame(Duration.millis(300),
new KeyValue(section_to_hide_container.prefWidthProperty(), 0),
new KeyValue(section_to_hide.translateXProperty(), -width),
new KeyValue(clip.translateXProperty(), width)
)
);
animation.setOnFinished(e -> {
// Removing the clips
clip.heightProperty().unbind();
section_to_hide.setClip(null);
//Hiding the panes at the end
section_to_hide_container.setVisible(false);
section_to_hide.setVisible(false);
});
animation.play();
}
#FXML
public void initialize() {
// Binding min/max to pref, to not allow the panes width change.
section_to_hide_container.minWidthProperty().bind(section_to_hide_container.prefWidthProperty());
section_to_hide_container.maxWidthProperty().bind(section_to_hide_container.prefWidthProperty());
section_to_hide.minWidthProperty().bind(section_to_hide.prefWidthProperty());
section_to_hide.maxWidthProperty().bind(section_to_hide.prefWidthProperty());
}
I wrote a detailed blog about this particular feature. Please do check to get more inputs on this. Also please note that this blog was written almost 10 years back with my knowledge at that time. So some code and wordings may not be relevant now :)
As #James_D noticed in the comments, you should check if an AchorPane is the right container for your needs. For the specific example, a StackPane may be better suited.
If you need to use an AchorPane, one way to hide the pane completely is by applying .setManaged(false) to the pane at the end of the animation:
animation.setOnFinished(e -> section_to_hide.setManaged(false));
As #Slaw noticed in the comments, you can also use a clip on the AnchorPane:
Rectangle clip = new Rectangle();
clip.widthProperty().bind(section_to_hide.widthProperty());
clip.heightProperty().bind(section_to_hide.heightProperty());
section_to_hide.setClip(clip);
I have a ScrollPane control with left and right parts inside. Left part contains a GridPane control. I would like to make the GridPane across the entire width of the parent VBox control.
For this purpose, I used a columnConstraints. Now, the GridPane is full-width, but the scrolling is broken. How can I fix it?
Please try the following sample with and without using the columnConstraints and you will see what I mean.
sample.FXML:
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.Text?>
<ScrollPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml"
fitToWidth="true"
fitToHeight="true">
<HBox>
<AnchorPane fx:id="leftPane"
minWidth="500"
prefWidth="500"
maxWidth="500"
style="-fx-background-color: orange">
<VBox style="-fx-background-color: lime"
AnchorPane.topAnchor="0"
AnchorPane.leftAnchor="0"
AnchorPane.rightAnchor="0"
AnchorPane.bottomAnchor="10">
<GridPane fx:id="gridPane"
style="-fx-background-color: brown">
<columnConstraints>
<ColumnConstraints />
<!-- This causes the trouble! -->
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
</GridPane>
<Label>Left Content</Label>
</VBox>
</AnchorPane>
<AnchorPane fx:id="rightPane"
HBox.hgrow="ALWAYS"
style="-fx-background-color: purple">
<Text>Right Content</Text>
</AnchorPane>
</HBox>
</ScrollPane>
with the corresponding Controller.java:
public class Controller implements Initializable {
#FXML
private GridPane gridPane;
private String[] splittedText;
#Override
public void initialize(URL location, ResourceBundle resources) {
// From Wikipedia
final String text = "Dolphins are a widely distributed and diverse group of aquatic mammals. They are an informal grouping within the order Cetacea, excluding whales and porpoises, so to zoologists the grouping is paraphyletic. The dolphins comprise the extant families Delphinidae (the oceanic dolphins), Platanistidae (the Indian river dolphins), Iniidae (the new world river dolphins), and Pontoporiidae (the brackish dolphins). There are 40 extant species of dolphins. Dolphins, alongside other cetaceans, belong to the clade Cetartiodactyla with even-toed ungulates.";
splittedText = text.split(" ");
for (int i = 0; i < 20; ++i) {
gridPane.add(new Text(Integer.toString(i)), 0, i);
gridPane.add(createFlowPane(), 1, i);
}
}
private FlowPane createFlowPane() {
FlowPane flowPane = new FlowPane();
for (int i = 0; i < splittedText.length; ++i)
flowPane.getChildren().add(new Text(splittedText[i]));
return flowPane;
}
}
I need some help. How do you center a text in HBox. I am using SceneBuilder. I try and I can't figure it out how to do it.
Here is the code for FXML.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Point3D?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Text?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<top>
<HBox prefHeight="50.0" prefWidth="800.0" BorderPane.alignment="CENTER">
<children>
<Text boundsType="LOGICAL_VERTICAL_CENTER" layoutX="600.0" layoutY="600.0" scaleZ="0.0" strokeType="OUTSIDE" strokeWidth="0.0" text="GIANTS DATABASE" textAlignment="CENTER" textOrigin="CENTER" wrappingWidth="231.7841796875" x="600.0" y="600.0">
<rotationAxis>
<Point3D x="1.0" y="1.0" z="1.0" />
</rotationAxis>
</Text>
</children></HBox>
</top>
<right>
<TableView prefHeight="550.0" prefWidth="577.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn minWidth="0.0" prefWidth="72.0" text="Rank" />
<TableColumn editable="false" minWidth="0.0" prefWidth="206.0" text="Name" />
<TableColumn editable="false" minWidth="0.0" prefWidth="88.0" text="Position" />
<TableColumn minWidth="0.0" prefWidth="77.0" text="School" />
<TableColumn minWidth="0.0" prefWidth="66.0" text="Age" />
<TableColumn minWidth="0.0" prefWidth="66.0" text="War" />
</columns>
</TableView>
</right>
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="3.0" right="3.0" />
</padding>
The text I want to center is GIANTS DATABASE, under HBox children
Here is the code for javaFX
public class Login extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/giants/LoginF.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Giants Database Login");
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e) {
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Here is the image of the text *GIANTS DATABASE. And I want to center the text where the arrow is pointing**
Remove the bounds, layoutX/Y and rotation settings on the Text node - they are not needed for this. What you are looking for is the HBox alignment property - setting it to Pos.CENTER will layout the children of the HBox in the center both vertically and horizontally. If you want to keep it to the left use Pos.CENTER_LEFT.
It is also not clear from your question whether you wish for the HBox to be this tall - it may be helpful to change the prefHeight of the HBox to Region.USE_COMPUTED_SIZE to have it match the size of the Text note (plus any padding/margins set on either of them).