在 JavaFX 中绑定字体大小?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23705654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bind Font Size in JavaFX?
提问by Taconut
I'd like to make my application fluid. However, the fonts look small compared to the UI elements when I make the windows bigger. Ultimately, I want the size of my text to get bigger or smaller when I resize the window. I know I could theoretically do this with the style property, but I already have that property bound to something else in some instances.
我想让我的应用程序流畅。但是,当我将窗口放大时,与 UI 元素相比,字体看起来很小。最终,当我调整窗口大小时,我希望文本的大小变大或变小。我知道理论上我可以用 style 属性来做到这一点,但在某些情况下我已经将该属性绑定到其他东西。
I know there's the "fontProperty" method, but I have nothing to bind it to since I can't figure out how to create a dynamic ObjectProperty with a synced size. What should I do?
我知道有“fontProperty”方法,但我没有任何东西可以绑定它,因为我不知道如何创建一个具有同步大小的动态 ObjectProperty。我该怎么办?
EDIT: To avoid confusion, I'm trying to make the Font size change based on other factors, not the other way around.
编辑:为了避免混淆,我试图根据其他因素来改变字体大小,而不是相反。
回答by jewelsea
Set the .root -fx-font-size
设置 .root -fx-font-size
- Create a custom stylesheetfor your application.
In sylesheet
.root
selector, set-fx-font-size
to your desired value:.root { -fx-font-size: 40px; }
- 为您的应用程序创建自定义样式表。
在 sylesheet
.root
选择器中,设置-fx-font-size
为您想要的值:.root { -fx-font-size: 40px; }
Why this works
为什么这有效
This works because:
这是有效的,因为:
- All of the default controls are based on
em
units (which are based on the default font size). -fx-font-size
is an inheritedstyle.- Everything inherits from the root.
Once you do this, all controls (and the text inside them) will automatically resize nicely to fit whatever font size you specified.
执行此操作后,所有控件(以及其中的文本)将自动调整大小以适合您指定的任何字体大小。
Related Sample
相关样本
Related Information
相关信息
em
is a generic unit that is not specific to JavaFX and em units are also used in HTML CSS. If interested, you can read a broader discussion on em units versus other units.
em
是一个不特定于 JavaFX 的通用单元,并且 em 单元也用于 HTML CSS。如果有兴趣,您可以阅读关于 em 单位与其他单位的更广泛的讨论。
Using em units in FXML via expression binding
通过表达式绑定在 FXML 中使用 em 单位
Just setting a default font size gets you about 90% of the way to where you need to be, but is not necessarily a universal fix as some layout units might be specified not using em units. Most of the time this isn't really an issue, but if it is in your case, you could also apply a mechanism described in an Oracle developer mailing list post, which appears to work, though is a little clunky.
仅设置默认字体大小就可以让您到达所需位置的大约 90%,但不一定是通用修复,因为某些布局单位可能指定为不使用 em 单位。大多数情况下,这并不是真正的问题,但如果是您的情况,您也可以应用Oracle 开发人员邮件列表帖子中描述的机制,该机制似乎有效,但有点笨拙。
How about using an expression binding.
如何使用表达式绑定。
For 35em x 25em you could write:
对于 35em x 25em,你可以这样写:
prefWidth="${35*u.em}" prefHeight="${25*u.em}"
It's not 100% concise, but perhaps passable.
它不是 100% 简洁,但也许还可以。
These kind of sizing expressions work in scene builder 1.1, which is nice.
这些大小表达式适用于场景构建器 1.1,这很好。
Here is an example using a Rectangle to store the width and height modifiers for the fxml file.
这是一个使用 Rectangle 存储 fxml 文件的宽度和高度修饰符的示例。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<StackPane xmlns:fx="http://javafx.com/fxml">
<fx:define>
<Rectangle fx:id="s" width="13" height="13"/>
</fx:define>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="${22 * s.width}" prefWidth="${14 * s.height}">
<children>
<Button layoutX="${4 * s.width}" layoutY="${ 5 * s.height}" prefWidth="${6 * s.width}" text="Top" />
<Button layoutX="${4 * s.width}" layoutY="${10 * s.height}" prefWidth="${6 * s.width}" text="Middle" />
<Button layoutX="${4 * s.width}" layoutY="${15 * s.height}" prefWidth="${6 * s.width}" text="Bottom" />
</children>
</AnchorPane>
</StackPane>
Or instead, you can create your own unit class and use it in your sizing expressions, for example:
或者,您可以创建自己的单元类并在大小表达式中使用它,例如:
package org.jewelsea.measure;
public class Measurement {
private double em;
public void setEm(double em) { this.em = em; }
public double getEm() { return em; }
}
. . .
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.jewelsea.measure.Measurement?>
<?scenebuilder-classpath-element .?>
<StackPane xmlns:fx="http://javafx.com/fxml">
<fx:define>
<Measurement fx:id="u" em="26.0" />
</fx:define>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="${22*u.em}" prefWidth="${14*u.em}">
<children>
<Button layoutX="${4*u.em}" layoutY="${ 5*u.em}" prefWidth="${6*u.em}" text="Top" />
<Button layoutX="${4*u.em}" layoutY="${10*u.em}" prefWidth="${6*u.em}" text="Middle" />
<Button layoutX="${4*u.em}" layoutY="${15*u.em}" prefWidth="${6*u.em}" text="Bottom" />
</children>
</AnchorPane>
</StackPane>
回答by brian
Just put everything where you want the fontsize to change in a container and set that style or use bindings if you want.
只需将所有您希望字体大小更改的内容放在容器中,然后设置该样式或根据需要使用绑定。
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class FontBind extends Application {
private DoubleProperty fontSize = new SimpleDoubleProperty(10);
private IntegerProperty blues = new SimpleIntegerProperty(50);
@Override
public void start(Stage primaryStage) {
Button btn = new Button("click me, I change color");
btn.setOnAction((evt)->{blues.set(blues.get()+20);});//max?
Label lbl = new Label("I'm a label");
TextArea ta = new TextArea("Lots of text can be typed\nand even number 1234567890");
HBox hbox = new HBox(new Label("I never change"));
VBox child = new VBox(btn, lbl, ta);
VBox root = new VBox(child, hbox);
Scene scene = new Scene(root, 300, 250);
fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
child.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString(), ";"
,"-fx-base: rgb(100,100,",blues.asString(),");"));
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm not sure what your style is already bound to, but you're allowed to set multiple css values in the style string.
我不确定您的样式已经绑定到什么,但是您可以在样式字符串中设置多个 css 值。
回答by jalopezsuarez
There is a simplest and proper method to bind font size with the container size, in order to make it in a responsive font scale effect.
有一个最简单且合适的方法将字体大小与容器大小绑定,以使其具有响应式字体缩放效果。
The bind(Bindings.concat("-fx-font-size: "
is a good alternative but when you resize the windows it seems to be very slow and I think is not the proper way to resolve the problem.
这bind(Bindings.concat("-fx-font-size: "
是一个不错的选择,但是当您调整窗口大小时,它似乎很慢,我认为这不是解决问题的正确方法。
You can declare FontProperty and bind this FontProperty to the Component (Label, Text, etc.) and finally create an event to bind the size with the FontProperty size according with our design:
您可以声明 FontProperty 并将此 FontProperty 绑定到组件(Label、Text 等),最后创建一个事件以根据我们的设计将大小与 FontProperty 大小绑定:
private Label textTracking = new Label();
private ObjectProperty<Font> fontTracking = new SimpleObjectProperty<Font>(Font.getDefault());
Then in constructor or some init method you can bind the font property of our object with our dynamic font:
然后在构造函数或某些 init 方法中,您可以将对象的字体属性与我们的动态字体绑定:
textTracking.fontProperty().bind(fontTracking);
Finally, you need to bind the wrapper container change size with the dynamic font size:
最后,您需要将包装容器更改大小与动态字体大小绑定:
widthProperty().addListener(new ChangeListener<Number>()
{
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldWidth, Number newWidth)
{
fontTracking.set(Font.font(newWidth.doubleValue() / 4));
}
});
With this solution the dynamic font adjustment is very flow and fast, even more than bind(Bindings.concat("-fx-font-size: "
method.
使用此解决方案,动态字体调整非常流畅和快速,甚至超过bind(Bindings.concat("-fx-font-size: "
方法。
回答by Alexandre
I had a similar problem and solved it this way:
我有一个类似的问题,并以这种方式解决了它:
- in the CSS and FXML files, I defined all font sizes in a relative way, using only "em" instead of "%" or "px"
- in the controller of the main window, I bound a double value within a style property of the main pane to some scene size property (e.g. a rough approximation of its diagonal length)
- 在 CSS 和 FXML 文件中,我以相对方式定义了所有字体大小,仅使用“em”而不是“%”或“px”
- 在主窗口的控制器中,我将主窗格的样式属性中的双精度值绑定到某个场景大小属性(例如其对角线长度的粗略近似值)
It works because the style that is set to the main pane will affect as a modifier all the nodes that are already defined in the FXML. The nodes that already have a style class are also impacted as the new style comes as an additional top layer of styling in the cascading style sheets.
它起作用是因为设置到主窗格的样式将作为修饰符影响 FXML 中已定义的所有节点。已经具有样式类的节点也会受到影响,因为新样式作为层叠样式表中的附加顶层样式出现。
The main advantage of this solution is to handle in a single place the font size zoom factor. Thus you don't have to find every node that has a Font property to make it working.
此解决方案的主要优点是在一个地方处理字体大小缩放系数。因此,您不必找到每个具有 Font 属性的节点来使其工作。
Sample files:
示例文件:
styles.css
样式文件
.label {
-fx-font-size: 1.1em;
}
.title {
-fx-font-size: 1.5em;
-fx-font-weight: bold;
}
main.fxml
主文件
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<BorderPane style="-fx-background-color: #fff;"
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1280.0" prefHeight="720.0"
fx:controller="controllers.MainController">
<top>
<Label text="Application title" styleClass="title"/>
</top>
<center>
<Label text="Lorem ipsum"/>
</center>
</BorderPane>
MainController.java
主控制器.java
package controllers;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.BorderPane;
public class MainController implements Initializable {
@FXML private BorderPane mainPane;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
initializeFontSizeManager();
}
private void initializeFontSizeManager() {
// Cf. https://stackoverflow.com/questions/13246211/javafx-how-to-get-stage-from-controller-during-initialization
mainPane.sceneProperty().addListener((observableScene, oldScene, newScene) -> {
// We need a scene to work on
if (oldScene == null && newScene != null) {
DoubleProperty fontSize = new SimpleDoubleProperty(0);
fontSize.bind(newScene.widthProperty().add(newScene.heightProperty())
.divide(1280 + 720) // I know, it's a very rough approximation :)
.multiply(100)); // get a suitable value to put before the '%' symbol in the style
mainPane.styleProperty().bind(
Bindings.concat("-fx-font-size: ", fontSize.asString("%.0f")).concat("%;"));
}
});
}
}