I have defined an FXML with a GridPane of 8 rows, which holds the following components (FXML and CSS definitions are given at the end of this thread):
2 CheckBoxes,
2 Labels,
2 Labels With a Region and
2 Buttons with A Region
The Region here is used to load images into, which is done through a CSS style. For each set of the components defined above (for example the 2 Checkboxes), I take the one and I increased it's size by using the -fx-font-size styling. In particular, I define the font size to be "1.3xDefault_System_Font_Size (12)". The tags (INC) and (DEF) in text of each component, is used to describe whether the font size is increased or left to the default value.
As you can see from the above screenshot, the label of checkbox is increased but the box itself did not. The same applies for the images, that their size did not increase but the label size did.
This gets worse when I change the default font size in .root:
.root{
-fx-font-size: 28;
}
In the example above, since I changed the default font size from 12 to 28, I expect all labels and images to change their size according to this new size. The image size is defined by the -fx-background-size which is 4em.
However, all the labels are increased correctly but the images are increased correctly only on those nodes with the DEF tag. The same applies for the checkbox, where it's label and box is increased on the DEF, whilst the one with the INC tag only label size increased correctly and the box remained small.
Is there a way to make images and box of checkbox to increase their size correctly? Is this a bug, or am I doing something wrong?
FXML: Gridpane
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane stylesheets="#css/Test.css" vgap="5.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ebay.client.controller.SettingsScreenController">
<children>
<CheckBox nodeOrientation="RIGHT_TO_LEFT" styleClass="increased_font" text="CheckBox (Inc)" GridPane.rowIndex="1" />
<CheckBox nodeOrientation="RIGHT_TO_LEFT" text="CheckBox (Def)" GridPane.rowIndex="2" />
<Label cache="true" styleClass="increased_font" text="Label (Inc)" GridPane.rowIndex="3" />
<Label cache="true" text="Label (Def)" GridPane.rowIndex="4" />
<Label cache="true" styleClass="increased_font" text="Label With Image (Inc)" GridPane.rowIndex="5">
<graphic><Region styleClass="javasuns_logo" /></graphic>
</Label>
<Label cache="true" text="Label With Image (Def)" GridPane.rowIndex="6">
<graphic><Region styleClass="javasuns_logo" /></graphic>
</Label>
<Button styleClass="increased_font" text="Button With Image (Inc)" GridPane.rowIndex="7">
<graphic><Region styleClass="javasuns_logo" /></graphic>
</Button>
<Button text="Button With Image (Def)" GridPane.rowIndex="8">
<graphic><Region styleClass="javasuns_logo" /></graphic>
</Button>
</children>
</GridPane>
CSS: Test.css
.increased_font {
-fx-font-size: 1.3em;
}
.javasuns_logo {
-fx-font-size: null;
-fx-pref-height: 2em;
-fx-pref-width: 4em;
-fx-background-image: url('../../icons/logo/javasuns.png');
-fx-background-size: 4em;
-fx-background-repeat: no-repeat;
-fx-background-position: center;
}
What I found is that when you're using pref-height and pref-width you cannot use -fx-font-size in the same class cause it "resets" the .root -fx-font-size to the default value of 12.
I wanted to set specific font-size in some buttons as well as setting the width and height using the em values. It wasn't possible so I created a Label inside the element of Button and here I can resize the label font-size correctly. So if I don't use the font-size and pref-width/height in the same class/same control it looks like it's working.
Related
I want to add spacing between the ComboBox and the TextField. I added spacing to the Box however since there are 4 nodes in the HBox, it adds spacing to all of them which isn't what I want. I want the TextField to be on the right of the window. I was thinking of adding an invisible separator with a large width however I read that regions can be used but I'm unsure on how to use them in FXML.
This is the code I have currently, but unsure how to add a region to it.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.TextFlow?>
<BorderPane prefHeight = "200.0" prefWidth = "300.0" xmlns =
<top>
<HBox alignment = "CENTER_LEFT" prefWidth = "300.0" spacing = "5">
<padding>
<Insets topRightBottomLeft="50" />
</padding>
<Label>Sort by: </Label>
<ComboBox fx:id = "sortOrder" promptText = "Select" />
</HBox>
</top>
</BorderPane>
Don't hard-code preferred sizes.
To make the text field sit at the right edge of the HBox, add an empty Region between the ComboBox and TextField. Set the region's hgrow parameter to ALWAYS, so any extra space will get allocated to it:
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.TextFlow?>
<BorderPane xmlns = "http://javafx.com/javafx/16" xmlns:fx = "http://javafx.com/fxml/1" >
<top>
<HBox alignment = "CENTER_LEFT" spacing = "5">
<padding>
<Insets topRightBottomLeft="20" />
</padding>
<Label>Sort by: </Label>
<ComboBox fx:id = "sortOrder" promptText = "Select" />
<Label>Search by host name: </Label>
<Region HBox.hgrow="ALWAYS" />
<TextField fx:id = "hostName" />
</HBox>
</top>
</BorderPane>
After stretching the window:
You can further control the behavior if you need; e.g. to let the text field grow, set it's maxWidth to Infinity and set the maxWidth of the Region. Other solutions are possible; e.g. put the label and combo box in a HBox, and then wrap the HBox and TextField in a BorderPane, with the HBox in the left and the TextField in the right.
I have a custom JavaFX component that is basically just a combination of a pane and textfield contained within a VBox.
What I want to do is have the bloody image turn brighter red when the textfield has focus or the mouse is over the VBox as a whole, because I think it would look nice. As of right now, my plan for this is just doing it programmatically. I am unaware of how I could do this using just CSS (Let me know if this is possible though, but this isn't related to the question).
The problem
The problem I am having is that when I try to resize the component along the x-axis using the component's pref width setting, the component doesn't visually stretch / resize, it just stays the same. When I change the pref size of the VBox in the original components fxml file, the textfield and pane expand as well. I could use CSS to set the pref width for all the elements within the custom component / the VBox in the CSS for scenes that would use the component, but I want to have the component automatically expand to fill their containers and I want so just easily be able to resize it within scene builder without changing CSS. Basically the underlying problem is I don't know how to get the VBox to resize when the component resizes. I was thinking I could add a custom field to do this but I am assuming there is an easier way of doing this, as the situation I am in would seem to be common, even if I can't find a solution for it when searching.
For reference here is the fxml for the custom component:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<VBox maxWidth="1.7976931348623157E308" styleClass="bloody-text-field" stylesheets="#../CSS/BloodyTextField.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="textField" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" />
<Pane fx:id="bloodyPane" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="35.0" minWidth="-Infinity" styleClass="bloody-pane" />
</children>
</VBox>
Here is the CSS for the custom component. The image shouldn't be important (Its just tileable in the x dimension) so I wont include it.
.bloody-text-field .text-field {
-fx-font-family: chiller;
-fx-font-size: 32px;
-fx-text-fill: #eb0900;
-fx-text-alignment: center;
-fx-alignment: center;
-fx-background-color: rgba(0.5, 0, 0, 0.0);
-fx-prompt-text-fill: #841200;
}
.bloody-text-field .bloody-pane {
-fx-background-repeat: repeat-x;
-fx-background-size: contain;
-fx-background-image: url("../Images/blood-drip-tileable.png");
}
Here is a fxml file that explains what I want to happen.
<?xml version="1.0" encoding="UTF-8"?>
<?import controls.BloodyTextField?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<BloodyTextField layoutX="32.0" layoutY="50.0" prefHeight="91.0" prefWidth="386.0" />
<Text layoutX="32.0" layoutY="45.0" strokeType="OUTSIDE" strokeWidth="0.0" text="I would expect this to expand until it fills the pref width" />
<VBox layoutX="32.0" layoutY="186.0" prefHeight="200.0" prefWidth="462.0">
<children>
<BloodyTextField />
<BloodyTextField />
</children>
</VBox>
<Text layoutX="32.0" layoutY="182.0" strokeType="OUTSIDE" strokeWidth="0.0" text="I would expect these two components to expand to fill the vbox's width" />
</children>
</Pane>
Thanks in advance for the guidance and help :)
I encountered the following issue using JavaFX.
Redefinition of tooltip style using stylesheet works in Java Scene Builder.
Redefinition of tooltip style at execution in eclipse with the same stylesheet included in FXML file generated from scene builder with
<stylesheets>
<URL value="#../style/myCSS.css" />
</stylesheets>
does not work (any other property redefinition works).
Redefinition of tooltip style at execution in eclipse with same stylesheet using code instruction :
scene.getStylesheets().add(this.getClass().getResource("/style/myCSS.css").toExternalForm());
works properly.
Stylesheet used (myCSS.css):
.tooltip {
-fx-background-radius: 2 2 2 2;
-fx-background-color: linear-gradient(#FFFFFF, #DEDEDE);
}
.page-corner {
-fx-shape: " ";
}
AnchorPane {
-fx-background-color: firebrick;
}
FXML file used:
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="91.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml">
<children>
<Button layoutX="72.0" layoutY="35.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button">
<tooltip>
<Tooltip text="Tootip Text" />
</tooltip>
</Button>
</children>
<stylesheets>
<URL value="#../style/myCSS.css" />
</stylesheets>
</AnchorPane>
Edit: In other words I want to be abe to declare my stylesheet in the FXML file. Doing so seems to work for any property redefinition (AnchorPane background color in this case) except tooltips.
The CSS properties you are trying to set for the Tooltip are only relavent to JavaFX classes that extend the Region class. The Tooltip is a child of the PopupControl class and, as such, has a more limited CSS property library. Here's a link to a list of available CSS properties for Tooltip. That site is your best reference for JavaFX CSS properties.
I have built a layout in SceneBuilder which has a ScrollPane (inside of a StackPane) containing a StackPane containing a Group (aligned to center-left) containing an ImageView. For some reason, whether I preview within SceneBuilder with Ctrl+P or run in my program, the horizontal scrollbar is disabled. The scrollbar does show that there is more to the right to be scrolled to, but I cannot scroll to it. It looks like this:
And here is the FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<center>
<StackPane prefHeight="150.0" prefWidth="200.0" style="-fx-background-color: white;" BorderPane.alignment="CENTER">
<children>
<ScrollPane id="scoreScrollPane" fitToHeight="true" hbarPolicy="ALWAYS" prefHeight="0.0" prefWidth="0.0" vbarPolicy="NEVER">
<content>
<StackPane alignment="CENTER_LEFT">
<children>
<Group id="scoreGroup" StackPane.alignment="CENTER_LEFT">
<children>
<ImageView id="scoreImage" fitHeight="150.0" fitWidth="3000.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#Untitled.png" />
</image>
</ImageView>
</children>
</Group>
</children>
</StackPane>
</content>
</ScrollPane>
<HBox id="toolbar" alignment="TOP_CENTER" prefHeight="100.0" prefWidth="200.0" spacing="8.0">
<children>
<Button id="recordButton" mnemonicParsing="false" text="Record" />
<Button id="stopButton" mnemonicParsing="false" text="Stop" />
</children>
<effect>
<DropShadow />
</effect>
</HBox>
</children>
</StackPane>
</center>
</BorderPane>
I've tried a horizontal scroll policy of both AS_NEEDED and ALWAYS.
You have numerous problems (most important is that the HBox with your controls covers your ScrollPane, intercepting that would otherwise go the ScrollPane):
Set preserveRatio="false" instead of preserveRatio="true" for your ImageView, otherwise the image may not grow to the fitWidth you provide (because it may hit the fitHeight limit first and not grow the width anymore).
Set maxHeight="-Infinity" on your HBox, (this will ensure that the maximum height of the HBox does not grow above the preferred height for the HBox, otherwise the HBox will intercept the mouse clicks intended for your ScrollPane). Either this, or set pickOnBounds="false" for the HBox, so that the HBox does not intercept mouse clicks for the ScrollPane even though it overlays the ScrollPane.
Note: to debug layout sizes, sometimes it is useful to temporarily add a background or border to a region to see it's true size, for example style="-fx-background-color: red;".
Also rather than placing your controls and image in a StackPane, which overlays content, maybe you might want to use a VBox instead, which instead lays things out vertically rather than on top of each other.
I want to make a vertical toolbar with buttons arranged vertically. Using JavaFX 2.2 that is included in JDK 7, in Linux Mint.
The screenshot shows the problem:
The FXML I am using looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<?language javascript?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane prefHeight="800.0" prefWidth="700.0" styleClass="root" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<ToolBar>
<items>
<Button text="Test" />
</items>
</ToolBar>
</top>
<left>
<ToolBar orientation="VERTICAL" style="-fx-background-color: blue;">
<items>
<Region style="-fx-padding:10;" />
<Button rotate="-90" text="Project" style="-fx-label-padding:1;"/>
<Region style="-fx-padding:10;" />
<Button rotate="-90" text="Structure" />
</items>
</ToolBar>
</left>
<center>
<HBox>
<children>
</children>
</HBox>
</center>
<bottom>
<ToolBar prefHeight="18.0" prefWidth="472.0">
<items>
<Region styleClass="spacer" />
<HBox>
<children>
</children>
</HBox>
</items>
</ToolBar>
</bottom>
</BorderPane>
The proper toolbar in my definition is: buttons are placed correctly and the toolbar is as wide as the width of the buttons. The blue color indicates how wide the toolbar currently is.
Wrap your rotated tool items in a Group, then the in-built layout of toolbar will know that the rotation is a permanent one which should be taken into account for layout calculations and not just a temporary thing which might be used for animations. Read the javadoc for Group, where it talks about layout bounds calculations to better understand this.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="100.0" style="-fx-background-color: cornsilk;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ToolBar orientation="VERTICAL" style="-fx-base: palegreen;">
<items>
<Group>
<children>
<Button rotate="-90.0" style="-fx-base: gold;" text="Project" />
</children>
</Group>
<Group>
<children>
<Button rotate="-90.0" style="-fx-base: khaki;" text="Structure" />
</children>
</Group>
</items>
</ToolBar>
</children>
</HBox>
Update 24th April 2017
The above solution is fine as far as it goes, but does suffer from an issue in that the buttons in the toolbar misalign when they receive focus.
What a group does is size itself based upon its contents. When the size of the contents changes, the size of the group also changes. When a button or control gets focus in JavaFX it gets a focus ring around the control. The display for the focus ring is defined in CSS and contains negative values for background inset display. The result is that, when a control is focused, it is slightly larger than when it is not focused. Normally, when you use a standard layout pane, this is not an issue as the layout pane will just ignore the background insets for layout purposes. A group however takes the full size into account and does not ignore the focus ring. The result is that a group that consists of only a control will change in size slightly when it is focused or unfocused. This presents an issue with the solution above because, when a button becomes focused, it will get slightly larger and the shift in layout in the toolbar, which is not ideal.
The solution to the focus shift problem in the above code is to just rotate the entire ToolBar within a group rather than rotating each button within a group per button. This works fine, but then presents some other issues such as the ToolBar not taking up the entire available area at the left side of the scene (due to wrapping it in a group removing the dynamic layout properties of the ToolBar). To get around this, a binding in code can be used to size the ToolBar to the available area of its parent layout container.
So we end up with the slightly more verbose solution below:
skinsample/toolbar.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ToggleGroup?>
<BorderPane fx:id="border" prefHeight="200.0" prefWidth="100.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="skinsample.VerticalToolbarController">
<left>
<Group>
<fx:define>
<ToggleGroup fx:id="selectedTool"/>
</fx:define>
<ToolBar fx:id="toolbar" rotate="-90.0" style="-fx-base: palegreen;">
<Pane HBox.hgrow="ALWAYS" />
<ToggleButton style="-fx-base: khaki;" text="Structure" toggleGroup="${selectedTool}"/>
<ToggleButton style="-fx-base: gold;" text="Project" toggleGroup="${selectedTool}" selected="true"/>
</ToolBar>
</Group>
</left>
</BorderPane>
skinsample/VerticalToolbarController.java
package skinsample;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
public class VerticalToolbarController {
#FXML
private BorderPane border;
#FXML
private ToolBar toolbar;
public void initialize() {
toolbar.minWidthProperty().bind(Bindings.max(border.heightProperty(), toolbar.prefWidthProperty()));
}
}
skinsample/ToolDisplayApp.java
package skinsample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ToolDisplayApp extends Application {
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("toolbar.fxml"));
Scene scene = new Scene(loader.load());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Notes:
This solution also demonstrates use of ToggleButtons rather than standard buttons within the ToolBar.
We also eliminate the default overflow behavior of the ToolBar (as it seems a little annoying in the vertical toolbar situation), using:
toolbar.minWidthProperty().bind(Bindings.max(border.heightProperty(), toolbar.prefWidthProperty()));
If you want to retain the overflow behavior, then use:
toolbar.prefWidthProperty().bind(border.heightProperty());
An alternate solution to the focus issue (using CSS to remove the focus ring entirely), is presented in:
JavaFX - How to prevent Toolbar from changing width on button state changes.