I am trying to define dynamic evaluated variables with fx:define, but I can't get a variable to be evaluated from another one, I don't know if it's even possible?
<GridPane hgap="${10*m.dp}" vgap="${10*m.dp}" xmlns="http://javafx.com/javafx/8.0.51" xmlns:fx="http://javafx.com/fxml/1">
<fx:define>
<Measurement fx:id="m" />
<!-- This works, but is not what I need -->
<Double fx:id="width" fx:value="300" />
<!-- This doesn't work -->
<!-- <Double fx:id="width" fx:value="${300*m.dp}" /> -->
</fx:define>
<padding>
<Insets bottom="$width" left="$width" right="$width" top="$width" />
</padding>
<Text text="hello" />
<Button GridPane.rowIndex="1" text="button" prefWidth="${300*m.dp}" />
<Button GridPane.rowIndex="2" text="button2" prefWidth="$width" />
</GridPane>
What I want here is to compute the width from my computed dp (Density independent pixel - value is 1 in HD screen, 2 in 4K screen, 0.xx on my 1600px width screen). The "width" variable I want is to be used in very many component in my real case, this is why I wanted a variable - for concision.
The java code to run it
public class Measurement {
private double dp;
public Measurement(){
Screen primary = Screen.getPrimary();
dp=primary.getBounds().getWidth()/1920;
}
/**
* Equivalent of 1 px in 1920.
*/
public double getDp(){
return dp;
}
public void setDp (double dp) {
this.dp = dp;
}
}
public class MApplication extends Application {
public static void main (String[] args) {
launch (args);
}
@Override
public void start (Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader();
Parent root = fxmlLoader.load(getClass().getResource("index.fxml").openStream());
Scene scene = new Scene(root, 300, 275);
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.show ();
}
}
Actually, it s not clear to me which and where expression can be used, I see many answers here :Is it possible to use arithmetic expression in FXML?
here:Bind Font Size in JavaFX?
and here: http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html#expression_binding
I don't understand in which case I can use the expression language,is there a specification?
Edited: I adedd a Link to javafx-8 documentation, And I removed my obsolete comment on javaFX-2
Too late bute this might be helpful for somebody. When you use <Double fx:id="width" fx:value="300"/>
inside a <fx:define>
block, FMXLLoader goes the declared type, Double
in this case, and tries to call the method Double.valueOf("300")
and this works since this call returns a Double
object with the value of 300.
When you use <Double fx:id="width" fx:value="${300*m.dp}"/>
, a NumberFormatException
will be thrown since the value "${300*m.dp}" doesn't represent a valid double value.
FXMLLoader evaluates the expressions that start with "${" only when the type is observable.
In order to bind a value to another in FXML, both of them should be observable properties. In your case, you can add the following property to Measurement
class:
public class Measurement {
public final DoubleProperty dp = new SimpleDoubleProperty();
public Measurement() {
Screen primary = Screen.getPrimary();
dp.set(primary.getBounds().getWidth() / 1920.0);
}
public double getDp() {
return dp.get();
}
public void setDp(double dp) {
this.dp.set(dp);
}
public final DoubleProperty widthProperty() {
if (width == null) {
width = new SimpleDoubleProperty();
width.bind(dp.multiply(300.0));
}
return width;
}
private DoubleProperty width;
public final double getWidth() {
return width == null ? 0 : width.get();
}
}
And then use it like this in your FXML:
<fx:define>
<Measurement fx:id="measurement"/>
</fx:define>
<Button prefWidth="${measurement.width}" />
Note: IMHO, I don't think you need to make Measurement
class instantiatable. There is no meaning of repeating the same measures and create a new instances in every FXML file. An alternative solution would be a class with a private constructor that holds static properties and used in FXML by calling <fx:factory>
or <fx:constant>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With