From 0c5fec7e610e08a984b34076694cfb88aefc7aef Mon Sep 17 00:00:00 2001 From: Rebecca Williams Date: Tue, 21 Jul 2026 20:47:41 +0100 Subject: [PATCH] Workaround to JFX21 bug causing transparent labels Should be reverted once moved to JFX25. Fix has to be applied to all widgets that set the text fill color using a setter. --- .../javafx/widgets/BaseLEDRepresentation.java | 10 ++++++++++ .../widgets/ByteMonitorRepresentation.java | 12 +++++++++++- .../javafx/widgets/CheckBoxRepresentation.java | 2 +- .../javafx/widgets/GroupRepresentation.java | 2 ++ .../javafx/widgets/JFXBaseRepresentation.java | 18 +++++++++++++++--- .../javafx/widgets/LabelRepresentation.java | 1 + .../javafx/widgets/RadioRepresentation.java | 2 +- .../widgets/SlideButtonRepresentation.java | 2 +- .../javafx/widgets/SymbolRepresentation.java | 1 + .../javafx/widgets/TabsRepresentation.java | 1 + .../widgets/TextSymbolRepresentation.java | 1 + .../widgets/TextUpdateRepresentation.java | 1 + 12 files changed, 46 insertions(+), 7 deletions(-) diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/BaseLEDRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/BaseLEDRepresentation.java index c75cdb1f86..d75068e970 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/BaseLEDRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/BaseLEDRepresentation.java @@ -229,6 +229,7 @@ public void updateChanges() { final Color color = JFXUtil.convert(model_widget.propForegroundColor().getValue()); label.setTextFill(color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); label.setFont(JFXUtil.convert(model_widget.propFont().getValue())); led.setStyle("-fx-stroke: " + JFXUtil.webRgbOrHex(model_widget.propLineColor().getValue())); @@ -279,12 +280,21 @@ else if (led instanceof Rectangle) { // Colors of text and LED are very close in brightness. // Make text visible by forcing black resp. white if (brightness > Brightness.BRIGHT_THRESHOLD) + { label.setTextFill(Color.BLACK); + setTextFillColorStyle(label, "#000000"); + } else + { label.setTextFill(Color.WHITE); + setTextFillColorStyle(label, "#FFFFFF"); + } } else + { label.setTextFill(text_color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); + } } } jfx_node.layout(); diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ByteMonitorRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ByteMonitorRepresentation.java index b26d8a8534..9a7ceca432 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ByteMonitorRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/ByteMonitorRepresentation.java @@ -143,6 +143,7 @@ private void addLEDs(final Pane pane, final double w, final double h, final bool label.getStyleClass().add("led_label"); label.setFont(text_font); label.setTextFill(text_color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); label.setManaged(false); } else @@ -436,12 +437,21 @@ public void updateChanges() { // Colors of text and LED are very close in brightness. // Make text visible by forcing black resp. white if (brightness > Brightness.BRIGHT_THRESHOLD) + { save_labels[i].setTextFill(Color.BLACK); + setTextFillColorStyle(save_labels[i], "#000000"); + } else + { save_labels[i].setTextFill(Color.WHITE); + setTextFillColorStyle(save_labels[i], "#FFFFFF"); + } } - else + else + { save_labels[i].setTextFill(text_color); + setTextFillColorStyle(save_labels[i], JFXUtil.webHex(model_widget.propForegroundColor().getValue())); + } save_labels[i].layout(); } } diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/CheckBoxRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/CheckBoxRepresentation.java index db73a336b6..e95b14f146 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/CheckBoxRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/CheckBoxRepresentation.java @@ -19,7 +19,6 @@ import org.csstudio.display.builder.model.widgets.CheckBoxWidget; import org.csstudio.display.builder.representation.javafx.JFXUtil; import org.epics.vtype.VType; -import org.phoebus.ui.javafx.Styles; import org.phoebus.ui.javafx.TextUtils; import javafx.application.Platform; @@ -223,6 +222,7 @@ public void updateChanges() jfx_node.setText(label); jfx_node.setFont(JFXUtil.convert(model_widget.propFont().getValue())); jfx_node.setTextFill(JFXUtil.convert(model_widget.propForegroundColor().getValue())); + setTextFillColorStyle(jfx_node, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); // Don't disable the widget, because that would also remove the // context menu etc. diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/GroupRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/GroupRepresentation.java index 04e1cd8cc9..ea1f87dbd9 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/GroupRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/GroupRepresentation.java @@ -215,6 +215,7 @@ public void updateChanges() label.setPadding(TITLE_PADDING); label.setPrefSize(width + ( ( !firstUpdate && hasChildren ) ? insets[2] : 0 ), inset); label.setTextFill(foreground_color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); label.setBackground(new Background(new BackgroundFill(line_color, CornerRadii.EMPTY, Insets.EMPTY))); break; } @@ -233,6 +234,7 @@ public void updateChanges() label.setPadding(TITLE_PADDING); label.setPrefSize(Label.USE_COMPUTED_SIZE, Label.USE_COMPUTED_SIZE); label.setTextFill(foreground_color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); label.setBackground(new Background(new BackgroundFill(background_color, CornerRadii.EMPTY, Insets.EMPTY))); break; } diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/JFXBaseRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/JFXBaseRepresentation.java index 2aac3a3e0e..b60aaf1e65 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/JFXBaseRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/JFXBaseRepresentation.java @@ -22,7 +22,6 @@ import org.csstudio.display.builder.model.Widget; import org.csstudio.display.builder.model.WidgetProperty; import org.csstudio.display.builder.model.properties.CommonWidgetProperties; -import org.csstudio.display.builder.model.widgets.GroupWidget; import org.csstudio.display.builder.model.widgets.TabsWidget; import org.csstudio.display.builder.model.widgets.TabsWidget.TabItemProperty; import org.csstudio.display.builder.representation.WidgetRepresentation; @@ -34,8 +33,6 @@ import javafx.scene.Cursor; import javafx.scene.Node; import javafx.scene.Parent; -import org.phoebus.core.types.ProcessVariable; -import org.phoebus.ui.dnd.DataFormats; import org.phoebus.ui.javafx.Styles; /** Base class for all JavaFX widget representations @@ -378,4 +375,19 @@ public void setDisabledLook(Boolean enabled, ObservableList children) { } } } + + /** + * Set the text fill using inline CSS + * TODO Remove this method after moving to JFX25!! + * It is Required in JFX21 to workaround bug https://bugs.openjdk.org/browse/JDK-8336097 + * meaning we cannot set the colour using setters after making the parent pane + * transparent. + * See Phoebus Github issue https://github.com/ControlSystemStudio/phoebus/issues/3891 + * + * @param node JFX node + * @param color Colour as hex string + */ + public static void setTextFillColorStyle(Node node, String color){ + node.setStyle("-fx-text-fill: "+ color); + } } diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/LabelRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/LabelRepresentation.java index 66b46fd532..f1419589c3 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/LabelRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/LabelRepresentation.java @@ -180,6 +180,7 @@ public void updateChanges() Color color = JFXUtil.convert(model_widget.propForegroundColor().getValue()); label.setTextFill(color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); if (model_widget.propTransparent().getValue()) label.setBackground(null); // No fill else diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/RadioRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/RadioRepresentation.java index c92fb5b4c8..746b005f9f 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/RadioRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/RadioRepresentation.java @@ -24,7 +24,6 @@ import org.epics.vtype.VEnum; import org.epics.vtype.VNumber; import org.epics.vtype.VType; -import org.phoebus.ui.javafx.Styles; import org.phoebus.ui.vtype.FormatOption; import org.phoebus.ui.vtype.FormatOptionHandler; @@ -304,6 +303,7 @@ public void updateChanges() { final RadioButton rb = (RadioButton) rb_node; rb.setTextFill(fg); + setTextFillColorStyle(rb, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); rb.setFont(font); } } diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SlideButtonRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SlideButtonRepresentation.java index 03d92d4bc7..947850ef3e 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SlideButtonRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SlideButtonRepresentation.java @@ -23,7 +23,6 @@ import org.csstudio.display.builder.model.widgets.SlideButtonWidget; import org.csstudio.display.builder.representation.javafx.JFXUtil; import org.epics.vtype.VType; -import org.phoebus.ui.javafx.Styles; import javafx.application.Platform; import javafx.geometry.Pos; @@ -94,6 +93,7 @@ public void updateChanges ( ) { label.setFont(JFXUtil.convert(model_widget.propFont().getValue())); label.setText(labelContent); label.setTextFill(foreground); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); // Don't disable the widget, because that would also remove the context menu etc. // Just apply a style that matches the disabled look. diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SymbolRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SymbolRepresentation.java index 41f319a755..f4f807e4b1 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SymbolRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/SymbolRepresentation.java @@ -434,6 +434,7 @@ protected StackPane createJFXNode ( ) throws Exception { indexLabel.setAlignment(Pos.CENTER); indexLabel.setFont(Font.font(indexLabel.getFont().getFamily(), FontWeight.BOLD, 16)); indexLabel.setTextFill(Color.WHITE); + setTextFillColorStyle(indexLabel, "#FFFFFF"); indexLabel.setVisible(model_widget.propShowIndex().getValue()); indexLabel.textProperty().bind(Bindings.convert(imageIndexProperty())); diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TabsRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TabsRepresentation.java index 9c35b35f3c..db6b669cb3 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TabsRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TabsRepresentation.java @@ -295,6 +295,7 @@ public void updateChanges() final Label label = (Label) tab.getGraphic(); label.setFont(tab_font); label.setTextFill(Color.BLACK); + setTextFillColorStyle(label, "#000000"); // Set colors tab.setStyle(style); diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextSymbolRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextSymbolRepresentation.java index d2fedb6f22..417dd88f48 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextSymbolRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextSymbolRepresentation.java @@ -223,6 +223,7 @@ protected Label createJFXNode ( ) throws Exception { ); symbol.setFont(JFXUtil.convert(model_widget.propFont().getValue())); symbol.setTextFill(JFXUtil.convert(model_widget.propForegroundColor().getValue())); + setTextFillColorStyle(symbol, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); symbol.setText("\u263A"); symbol.setManaged(false); diff --git a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextUpdateRepresentation.java b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextUpdateRepresentation.java index 6d91069f48..af5c2f8983 100644 --- a/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextUpdateRepresentation.java +++ b/app/display/representation-javafx/src/main/java/org/csstudio/display/builder/representation/javafx/widgets/TextUpdateRepresentation.java @@ -255,6 +255,7 @@ public void updateChanges() final Label label = (Label) jfx_node; Color color = JFXUtil.convert(model_widget.propForegroundColor().getValue()); label.setTextFill(color); + setTextFillColorStyle(label, JFXUtil.webHex(model_widget.propForegroundColor().getValue())); label.setFont(JFXUtil.convert(model_widget.propFont().getValue())); label.setAlignment(pos); label.setWrapText(model_widget.propWrapWords().getValue());