How to lookup the applied font on JavaFX Label? - css

I need to automatically resize the font on my JavaFX Label if the text doesn't all fit in the label's boundaries. I found some awesome code online (here Resize JavaFX Label if overrun) to do this but the problem is the code takes font size and as an argument. It seems like determining the font size would be very easy, but Label.getFont() returns the default settings because my application is using css to set the font sizes. My css is setting the font size to 30, but everything I have figured out how to look up on the Label so far is returning default settings of 12.
So I tried looking it up but I don't understand where to look for it. Label.getStyle() returns an empty string. getCSSMetaData() returns a whole bunch of interesting settings and I was able to find font there and look at the sub properties, but again it is storing the default values of font size 12 and a different style name.
This is the setting from my style sheet file that I'm using so I know I need to locate feedback card and font size:
._Feedback_Card {
-fx-font-size: 30px;
-fx-font-weight: bold;
-fx-text-fill: rgba(0,0,0,.9);
-fx-background-color: white;
-fx-border-color: white;
-fx-border-width: 0;
-fx-alignment: center;
-fx-text-alignment: center;
-fx-font-family: Arial Unicode MS;
-fx-effect: dropshadow(gaussian, #b4b4b4, 6,0,0,2);
}
Don't be swayed by the name, there's a mapping somewhere else in the code that maps this component to that class name somehow. It's written by a co-worker so I'm unaware of the exact mechanics. But given that name I tried looking up the region on the root node with:
Region node = (Region)jsLayoutCollection.jsDisplayLayoutCollection.fGetFXParent().lookup("._Feedback_Card");
String sStream = node.getCssMetaData().stream()
and then I looked through the stream for font properties. But that again returned font but the size was the default 12, not 30 that the style sheet sets it to.
So where is this property being applied and how do I look it up? It seems like it should be straightforward to figure out this information but I can't find it. It's very easy to set the font after with:
Label.setStyle("-fx-font-size: " + fontSize + "px");
Any help is greatly appreciated.

Once the stylesheet has been loaded by the label's scene (or parent), and CSS has been applied, getFont() will return the font set by CSS.
This code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class GetCSSFont extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Big label");
StackPane root = new StackPane(label);
Scene scene = new Scene(root);
scene.getStylesheets().add("set-font.css");
System.out.println("Default font: "+label.getFont());
label.applyCss();
System.out.println("Font from CSS: "+label.getFont());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with set-font.css:
.label {
/* Note the font family needs quoting if it has spaces: */
-fx-font-family: 'Arial Unicode MS' ;
-fx-font-size: 30px ;
-fx-font-weight: bold ;
}
.root {
-fx-padding: 20 ;
}
produces the output:
Default font: Font[name=System Regular, family=System, style=Regular, size=13.0]
Font from CSS: Font[name=Arial Unicode MS, family=Arial Unicode MS, style=Regular, size=30.0]
(And you can, of course, get the point size with double size = label.getFont().getSize().)

Related

Different behavior of Text and Labeled controls in combination with css

I am working on a Javafx application and I tried to add some Labels, Buttons and Texts, which resizes when the user resizing the Scene. All Nodes are inside a VBox, which itself is inside a StackPane.
My test application:
public class Test extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(final Stage primaryStage)
{
StackPane pane = new StackPane();
VBox box = new VBox();
box.setAlignment(Pos.CENTER);
Label l = new Label("Label");
Text t = new Text("Text");
t.getStyleClass().add("test");
Button b = new Button("Button");
pane.heightProperty().addListener(listener ->
{
double h = pane.getHeight()/5;
l.setFont(Font.font(l.getFont().getFamily(), h));
t.setFont(Font.font(t.getFont().getFamily(), h));
b.setFont(Font.font(b.getFont().getFamily(), h));
});
box.getChildren().addAll(l, t, b);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane));
primaryStage.getScene().getStylesheets().add(Path.of("test.css").toUri().toString());
primaryStage.show();
}
}
If I resize the Stage it works as expected. But unfortunately only with pure Java code.
Because after adding my css file, the Labeled controls behave different. While the Text elements continue to change in size, the Labels and Buttons does not change their size anymore.
My css file, which does not work:
.label
{
-fx-text-fill: red;
-fx-font-family: impact;
}
.test
{
-fx-fill: red;
-fx-font-family: impact;
-fx-font-size: 2em;
}
.button
{
-fx-text-fill: red;
-fx-font-size: 2em;
}
I asked myself what I did wrong and have tested different css states. I found out, when I omit font values in css it works, otherwise it does not. Therewhile it does not matter which font value occurs, only one font value is required to miss the behavior.
My css file, which works:
.label
{
-fx-text-fill: red;
//-fx-font-family: impact;
}
.test
{
-fx-fill: red;
-fx-font-family: impact;
-fx-font-size: 2em;
}
.button
{
-fx-text-fill: red;
//-fx-font-size: 2em;
}
1. Question: -has changed, see below-
Do I missunderstand something about css and Javafx, or did I something wrong in my css file or is there a bug?
2. Question: -solved-
Have I to put the font values with java code or is there an other way to add the font?
Thank You for helping!
Update
As recommended I have studying the follow guide:
https://openjfx.io/javadoc/14/javafx.graphics/javafx/scene/doc-files/cssref.html
The JavaFX CSS implementation applies the following order of precedence:
The implementation allows designers to style an application by using style sheets to override property values set from code. For example, a call to rectangle.setFill(Color.YELLOW) can be overridden by an inline‑style or a style from an author stylesheet. This has implications for the cascade; particularly, when does a style from a style sheet override a value set from code? The JavaFX CSS implementation applies the following order of precedence: a style from a user agent style sheet has lower priority than a value set from code, which has lower priority than a Scene or Parent style sheet. Inline styles have highest precedence. Style sheets from a Parent instance are considered to be more specific than those styles from Scene style sheets.
In my case this means, I will use the inline style to make it proper.
thus the 2. Question is solved
But, because of Parent style sheet > value set from code, it also means, all Nodes are not allowed to change theire size, even the Text Node.
Therefore I changed my 1. Question to:
Why does the JavaFX CSS order of precedence differ between Text and Controls
Question 1:
It's not a bug, it's a conflict of priorities. .setFont() has a lower priority than that CSS. Just replace .setFont() to .setStyle() and sample will work as you planned:
l.setStyle("-fx-font-size:" + h + ";");
t.setStyle("-fx-font-size:" + h + ";");
b.setStyle("-fx-font-size:" + h + ";");
Question 2:
Try to keep all about styles in CSS. It's the best practice.

Change font color in JavaFX via .css file

Can someone please tell me why -fx-text-fill in the below example doesn't work to change the font color? -fx-stroke is something I've tried as well. Thanks!
Java File:
package SimpleTextFromCSS;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Main extends Application
{
#Override
public void start(Stage primaryStage)
{
GridPane rootGP = new GridPane();
Label centerText = new Label("Sample text.");
rootGP.getChildren().add(centerText);
Scene scene = new Scene(rootGP,1200,800);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(mainScene);
primaryStage.show();
}
}
public static void main(String[] args)
{
launch(args);
}
}
CSS:
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-text-fill: blue;
}
As pointed out in the comments (thanks to #Slaw), the -fx-text-fill property is not inherited by default, so setting it for your root pane will not allow it to propagate down to the labels in your UI. A possible fix would be to define the property for, say .label, but a better approach is to hook into the "theming" functionality of the default style sheet ("modena"). Admittedly, the documentation on this is pretty thin, but reading the comments in the CSS source code, particularly at the top of the file, indicate how this is intended to work.
Modena defines a "looked-up color" called -fx-text-background-color, which is used for text painted on top of a background filled with -fx-background-color. A Label is such a text, and the default style sheet sets the text fill of a label to -fx-text-background-color.
So one approach is to redefine the -fx-text-background-color value:
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-text-background-color: blue;
}
If you want to be a little more sophisticated, the default value of -fx-text-background-color is actually a "ladder", which picks a color depending on the intensity of the background. It is itself defined in terms of three other colors:
-fx-light-text-color (for dark backgrounds, which defaults to white),
-fx-mid-text-color (for light backgrounds, which defaults to a light grey), and
-fx-dark-text-color (for medium backgrounds, which defaults to black).
So if you want a solution that would be visually robust to changes in the background of a label, you could do
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-dark-text-color: navy ;
-fx-mid-text-color: blue ;
-fx-light-text-color: skyblue ;
}

Change Attributes jfx Decorator

I have initialized a decorator into my project, which was at first fine and nice looking. But now I have encountered several problems, I did not figure out how to change the border color (currently it is black). I also want to remove the button which resizes the window.
Here is the code which touches the decorator:
public void start(Stage primaryStage){
JFXDecorator decorator = new JFXDecorator(primaryStage, gridContainer);
decorator.setCustomMaximize(false);
decorator.setText("Window Title");
decorator.setStyle("-fx-background-color: #ffffff; -fx-font-family:'Franklin Gothic Medium'");
Scene scene= new Scene(decorator, 350, 500, Color.BEIGE);
}
A couple of minutes later I came up with a simple but adequate solution. I have created a decorator class in my css file.
Here is the code I have added into my css file:
.jfx-decorator{
-fx-decorator-color: white;
}
.jfx-decorator .jfx-decorator-buttons-container{
-fx-background-color: -fx-decorator-color;
}
.jfx-decorator .resize-border{
-fx-border-color: -fx-decorator-color;
-fx-border-width: 0 4 4 4;
}

How to change the icon size of a color picker in JavaFX?

How to change the icon size of a color picker in javaFX. I'm having a problem, I can not increase the icon size of a color picker in JavaFX, does anyone know how to change the size of the button icon?
icon its small :(
Setting the CSS attributes -fx-color-rect-width and -fx-color-rect-width will change size of the rectangle displayed. Setting fx-font-size will change the size of the arrow.
Note that some of these attributes are not documented in the official JavaFX CSS reference, so I guess future JavaFX iterations could change them without notice. Still, at this stage, I think that is probably unlikely and the attributes are pretty safe to use. To determine the undocumented CSS attributes, I looked at the source code for the ColorPickerSkin.
pickme.css
.large-rect-picker {
-fx-color-rect-width: 60px;
-fx-color-rect-height: 60px;
-fx-color-label-visible: false;
-fx-min-width: 150px;
-fx-min-height: 100px;
-fx-pref-width: 150px;
-fx-pref-height: 100px;
}
.large-rect-picker > .arrow-button {
-fx-font-size: 30px;
}
PickMe.java
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.stage.Stage;
public class PickMe extends Application {
#Override
public void start(Stage stage) {
ColorPicker colorPicker = new ColorPicker();
colorPicker.getStyleClass().add("large-rect-picker");
stage.setScene(new Scene(new Group(colorPicker)));
stage.getScene().getStylesheets().add(
PickMe.class.getResource(
"pickme.css"
).toExternalForm()
);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Aside info on asking questions
It is difficult to know exactly what you want as you aren't really explicit in the question. For instance what do you mean by icon? The rectangle or the down arrow or both? What about the display that is popped up when you click on that arrow, should that change at all or stay the same? For future questions, I recommend you be more specific about what you are trying to achieve and how it differs from what you have. Showing code which produces what you have might also help others solve your issue. Hopefully the info above is enough for you to modify it to accomplish what you wish.
You can access and customize color picker by using css:
ColorPicker
Style class: color-picker
Substructure
color display node — Label
arrow-button — StackPane
arrow — StackPane
The ColorPicker control has all the properties and pseudo‑classes of ComboBase
Example
.color-picker .label {
-fx-background-color: red;
-fx-text-fill: null;
-fx-graphic: url("1487868456_Other_Antivirus_Software.png");//This is icon of Color picker label
}
Result:
As far as I know you cant use -fx-width/-fx-height at all and you cant use percentage values for it. The width and height of elements are read-only. You can set -fx-pref-width, -fx-pref-height, -fx-max-width, -fx-min-width, -fx-max-height, -fx-min-height ,-fx-border-width and -fx-border-height to adjust the size of Java FX elements.
.picker-color {
-fx-border-color:white ;
-fx-border-width:40;
}

JavaFX - How to set Custom font to javaFX controls? [duplicate]

Firstly, I am quite a new guy in coding. I need to embed a font in my java FXML-based app and don't know how to do it. I have pasted the font, fontName.ttf in a "resources" folder in the root of the sources of my project, ie App/src/app/resources. I have set the CSS for the component (text) as
#text {
-fx-font-family: url(resources/fontName.ttf);
}
I have also tried adding inverted commas in the url, ie url("resources/fontName.ttf");, but it doesn't work. I have also set the CSS id for the component, so that can't be the problem. Is there any other working way to do so? I have seen http://fxexperience.com/2010/05/how-to-embed-fonts/, but it doesn't work since I have JDK 1.7 u21. Any ideas for a correct way to embed fonts?
Solution Approach
I updated the sample from Javafx How to display custom font in webview? to demonstrate using a custom true-type font in JavaFX controls styled using CSS.
Key points are:
Place the font in the same location as your application class and ensure your build system places it in your binary build package (e.g. application jar file).
Load the code font in your JavaFX code before you apply a style which uses it.
Font.loadFont(CustomFontApp.class.getResource("TRON.TTF").toExternalForm(), 10);
To use the custom font in a style class use the -fx-font-family css attribute and just reference the name of the font (e.g. in this case "TRON").
Create and load a stylesheet which defines the style classes.
Apply style classes to your controls.
Additional Information
If you are using Java 8, you may be interested in Use web(Google) fonts in JavaFX.
Font Collections
If your font file is in .ttc format, containing multiple fonts in a single file, then use the Font.loadFonts API (instead of Font.loadFont). Note that Font.loadFonts is only available since JDK 9 and is not available in earlier releases.
Sample Output Using a Custom Font
Sample Code
The example relies on a TRON.TTF font which you can download from dafont.
CustomFontApp.java
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.scene.text.*;
import javafx.stage.Stage;
// demonstrates the use of a custom font.
public class CustomFontApp extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
stage.setTitle("TRON Synopsis");
// load the tron font.
Font.loadFont(
CustomFontApp.class.getResource("TRON.TTF").toExternalForm(),
10
);
Label title = new Label("TRON");
title.getStyleClass().add("title");
Label caption = new Label("A sci-fi flick set in an alternate reality.");
caption.getStyleClass().add("caption");
caption.setMaxWidth(220);
caption.setWrapText(true);
caption.setTextAlignment(TextAlignment.CENTER);
VBox layout = new VBox(10);
layout.setStyle("-fx-padding: 20px; -fx-background-color: silver");
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(
title,
new ImageView(
new Image(
"http://ia.media-imdb.com/images/M/MV5BMTY5NjM2MjAwOV5BMl5BanBnXkFtZTYwMTgyMzA5.V1.SY317.jpg"
)
),
caption
);
// layout the scene.
final Scene scene = new Scene(layout);
scene.getStylesheets().add(getClass().getResource("custom-font-styles.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
}
custom-font-styles.css
/** file: custom-font-styles.css
* Place in same directory as CustomFontApp.java
*/
.title {
-fx-font-family: "TRON";
-fx-font-size: 20;
}
.caption {
-fx-font-family: "TRON";
-fx-font-size: 10;
}
On FXML Usage
Font.loadFont(url, size) is a static method taking two parameters. I don't think you can invoke font.loadFont from FXML and wouldn't advise it if you could. Instead, load the font in Java code (as I have done in my answer) before you load your FXML or style sheet which requires the font.
I know you didn't ask for a pure programmatic way to use a custom TTF font in a java fx application but i thought maybe it helps someone to see a programmatic version:
public class Test2 extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(final Stage primaryStage) {
Group rootGroup = new Group();
// create a label to show some text
Label label = new Label("Demo Text");
try {
// load a custom font from a specific location (change path!)
// 12 is the size to use
final Font f = Font.loadFont(new FileInputStream(new File("./myFonts/TRON.TTF")), 12);
label.setFont(f); // use this font with our label
} catch (FileNotFoundException e) {
e.printStackTrace();
}
rootGroup.getChildren().add(label);
// create scene, add root group and show stage
Scene scene = new Scene(rootGroup, 640, 480, Color.WHITE);
primaryStage.setScene(scene);
primaryStage.show();
}
}
That did the job for me. You can place the font wherever you want just make sure you adapt the path.
You can find a lot more about using fonts inside java fx apps here.
HTH

Resources