I've solved the problem to bring an icon image into the header of a TitledPane like this:
<TitledPane fx:id="x2" text="Strukturen">
<graphic>
<ImageView >
<image>
<Image url="#/de/myres/icons/arrow-out.png" />
</image>
</ImageView>
</graphic>
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0"
prefHeight="180.0" prefWidth="200.0" />
</content>
</TitledPane>
This looks like the following:
As you can see, it looks not very nice when the arrow for collapsing and this icon are shown beside each other directly.
How can i achieve to get the icon to the right side of the title bar?
You could leave the TitledPane text blank and set the icon node to be an HBox containing a Label on the left and an ImageView on the right.
Related
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 am looking for an elegant way of setting a padding to a TabPane, but without padding the tab bar:
<TabPane>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Tab text="red">
<Rectangle fill="RED" width="200" height="200" />
</Tab>
<Tab text="blue">
<Rectangle fill="BLUE" width="200" height="200" />
</Tab>
</TabPane>
gives:
however,
<TabPane>
<Tab text="red">
<VBox>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Rectangle fill="RED" width="200" height="200" />
</VBox>
</Tab>
<Tab text="blue">
<VBox>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Rectangle fill="BLUE" width="200" height="200" />
</VBox>
</Tab>
</TabPane>
gives:
which is exactly what i want, however I want to simplify the FXML structure, mainly by refactoring the <padding> element so it's declared in one place (shorter and non-repeating code) and not in every tab of the pane.
So is there any way to achieve this? Or am I stuck with my repeated <padding> elements? I'd prefer an FXML solution, but if no way exists a Java one is OK.
In a word: no.
Each Tab of the TabPane accepts a Node for it's contentProperty. The content itself is not a Region and therefore cannot have Insets or padding applied to it. The TabPane itself does not contain a method that allows you to style the content of all the child Tabs at once.
You must first add a container of some sort to the Tab in order to apply padding. So the second method in your question is the simplest way to accomplish what you are trying to do.
A Workaround
While this cannot be done with FXML, you could use a Java loop to add the same padding to all of your Tab objects after loading the scene:
Insets insets = new Insets(10);
for (Tab tab : tabPane.getTabs()) {
((VBox) tab.getContent()).setPadding(insets);
}
This assumes, of course, that you use a VBox for the content of all your tabs.
EDIT: I updated the answer to use the CSS selectors from fabian's comment down below.
You can set padding for most JavaFX scene graph objects in a separate css file. You will need to link the css file to your FXML file which I will show below. The css file and the FXML file will need to be in the same directory, otherwise you will have to edit the value="..." tag.
style.css
.tab-pane > .tab-content-area > * {
-fx-padding: 10 10 10 10;
}
This sets padding to all the VBoxes that happen to be under a Tab somewhere (no matter how deep in the hierarchy)
main.fxml
<TabPane>
<Tab text="red">
<VBox>
<Rectangle fill="RED" width="200" height="200" />
</VBox>
</Tab>
<Tab text="blue">
<VBox>
<Rectangle fill="BLUE" width="200" height="200" />
</VBox>
</Tab>
<stylesheets>
<URL value="#style.css" />
</stylesheets>
</TabPane>
I have problem and don't have any idea how to solve it.
I have button and I need to add image next to text on right. I did it but after resizing this button, image is always next to text. There is any solution to get text toleft and image to right side of button? (like on screenshot from scenebuilder)
FXML code:
<Button fx:id="btn1" alignment="BASELINE_LEFT" contentDisplay="RIGHT" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="50.0" text="Text">
<graphic>
<ImageView fitHeight="24.0" fitWidth="24.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="/images/User/user.png" preserveRatio="false" smooth="false" />
</image>
</ImageView>
</graphic>
</Button>
Background
In general, I'd advise, just using the ContentDisplay on buttons and having the button manage the layout of items inside the button on your behalf. But that approach will not work for your particular use-case.
Sample Solution
Put both the text and the image in the graphic inside your own layout manager (for example an HBox). This way you have the flexibility to apply a custom layout to the button, allowing you to situate the text and image exactly as you wish.
In the sample solution I add a Pane between the text and the graphic with a hgrow constraint of always, so that the pane will act as an expandable invisible spacer between the the text and the image, pushing them as far apart from each other horizontally as is possible (within the constraints of the overall button size).
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button contentDisplay="RIGHT" mnemonicParsing="false" prefHeight="98.0" prefWidth="259.0" style="-fx-base: thistle;">
<graphic>
<HBox alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mouseTransparent="true">
<children>
<Label text="Nightshade">
<font>
<Font name="Papyrus" size="24.0" />
</font></Label>
<Pane HBox.hgrow="ALWAYS" />
<ImageView>
<image>
<Image url="#Potion-icon.png" />
</image>
</ImageView>
</children>
</HBox>
</graphic>
</Button>
</children>
</StackPane>
I want to set my button icon using some geometry shapes, such as circle, square, etc.
I also want to set it in FXML something like:
<Button .....>
<graphics>
<group>
<shape>
......
</shape>
</group>
</graphics>
</Button>
Is it possible? I do know how to load image icon into ImageView then setGraphic.
TIA
The graphic in a button can be any Node. A Shape such as a Circle is a Node.
So just set the button graphic to the shape. You can even put many shapes in a container such as a VBox or StackPane and set the button's graphic to the container so the graphic consists of many shapes.
Here is a sample FXML file you can copy and paste and load up in SceneBuilder 2.
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<VBox spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Panic">
<graphic>
<Circle fill="RED" radius="8.0" stroke="BLACK"/>
</graphic>
</Button>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="All OK">
<graphic>
<StackPane>
<children>
<Rectangle arcHeight="5.0" arcWidth="5.0" fill="LEMONCHIFFON" height="15.0" stroke="BLACK"
strokeType="INSIDE" width="15.0"/>
<SVGPath
content="M 1.3657704,4.938667 C 1.1462945,5.1582921 1.1462945,5.5133282 1.3657704,5.7329533 L 3.7236648,8.0924507 C 3.9431407,8.3120765 4.2979355,8.3120765 4.5174113,8.0924507 L 9.5366913,3.0697579 C 9.7561672,2.8501328 9.7561674,2.4950969 9.5366913,2.2754716 L 8.6962538,1.4344625 C 8.4767779,1.2148374 8.121983,1.2148374 7.9025071,1.4344625 L 4.6107933,4.7284147 L 3.4902099,3.6070693 C 3.270734,3.3874441 2.9159392,3.387444 2.6964632,3.6070693 L 1.3657704,4.938667 z"
fill="GREEN"/>
</children>
</StackPane>
</graphic>
</Button>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
</VBox>
I was wondering How one can achieve following button style where text resides underneath of image in JavaFx?
I tried a lot but all in vain. Any help would be appreciated.
The key is the contentDisplay property, set it to "TOP".
With fxml:
<Button contentDisplay="TOP" layoutX="101.0" layoutY="51.0" mnemonicParsing="false" text="Button">
<graphic>
<ImageView mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#image.png" preserveRatio="false" smooth="false" />
</image>
</ImageView>
</graphic>
</Button>
Or CSS:
.your-selector {
-fx-content-display: top;
}
Check the CSS reference here.
You can simply achieve that just by doing
Button b = new Button("text", graphics);
b.setContentDisplay(ContentDisplay.TOP);
And for cool icons, take a look at http://fxexperience.com/controlsfx/features/ it include icone from FontAwesome and IcoMoon