skip to Main Content

I’m encountering a problem while attempting to change the text color within a Hyperlink object embedded in a JavaFX Alert (with ExpandableContent).

Furthermore, I’d like to highlight that the CSS file is added to the DialogPane (indeed, background color and other formatting are correctly recognized).

My CSS class: alert_001

Despite several attempts I have been unable to achieve the desired outcome.
The text color of the Hyperlink remains unchanged within the Alert object.

DialogPane (dialog-pane)
+- ButtonBar (button-bar)
+--- HBox (container)
+------ Hyperlink (details-button more)(pseudo class state: visited)
+--------- LabeledText (text)
.alert_001 .dialog-pane .button-bar .container .details-button .more .text {
    -fx-text-fill: #bbbbbb;
    -fx-font-size: 12.0pt;
}

Thank you in advance

Minimal reproducible example

Create a new Java project (Java 8, no Gradle)

Main class (Directory: src, Package: my.project, File: Main.java)

package my.project;

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {

        final AlertComposer alertComposer = new AlertComposer();

        try {

            throw new Exception("Test");

        } catch (Exception e) {

            alertComposer.exception(e);
            throw new RuntimeException(e);

        }
    }
}

Alert composer class (Directory: src, Package: my.project, File: AlertComposer.java)

package my.project;

import javafx.scene.control.Alert;
import javafx.scene.control.DialogPane;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;

import java.io.PrintWriter;
import java.io.StringWriter;

public class AlertComposer {

    public void exception(Exception e) {

        String content = e.getMessage();
        Alert alert = this.build(Alert.AlertType.ERROR, "myTitle", "myHeader", content);

        GridPane expContent = buildExceptionGridPane(e);

        alert.getDialogPane().setExpandableContent(expContent);
        alert.showAndWait();
    }

    private GridPane buildExceptionGridPane(Exception e) {

        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        String exceptionText = sw.toString();

        TextArea textArea = new TextArea(exceptionText);
        textArea.setEditable(false);
        textArea.setWrapText(true);

        textArea.setMaxWidth(Double.MAX_VALUE);
        textArea.setMaxHeight(Double.MAX_VALUE);
        GridPane.setVgrow(textArea, Priority.ALWAYS);
        GridPane.setHgrow(textArea, Priority.ALWAYS);

        GridPane expContent = new GridPane();
        expContent.setMaxWidth(Double.MAX_VALUE);
        expContent.add(textArea, 0, 0);

        return expContent;
    }

    public Alert build(Alert.AlertType type, String title, String header, String content) {

        Alert alert = build(type);

        alert.setTitle(title);
        alert.setHeaderText(header);
        alert.setContentText(content);

        return alert;
    }

    private Alert build(Alert.AlertType type) {

        Alert alert = new Alert(type);

        DialogPane dialogPane = alert.getDialogPane();
        dialogPane.setMinHeight(Region.USE_PREF_SIZE);

        dialogPane.getStylesheets().add(Main.class.getResource("/theme.css").toExternalForm());
        dialogPane.getStyleClass().add("alert_001");

        return alert;
    }
}

Theme CSS (Directory: resources, File: theme.css)

.alert_001 {
    -fx-background-color: #282828;
}

.alert_001 .header-panel {
    -fx-background-color: #45494a;
}

.alert_001 .label {
    -fx-text-fill: #bbbbbb;
    -fx-font-size: 12.0pt;
}

.alert_001 .button {
    -fx-border-color: #5e6060;
    -fx-border-radius: 10.0 10.0 10.0 10.0;
    -fx-background-color: #3c3f41;
    -fx-background-radius: 10.0 10.0 10.0 10.0;
    -fx-text-fill: #bbbbbb;
    -fx-font-size: 14.0pt;
}

Text color to change

Alert text color to change

2

Answers


  1. You can style the color of the more or less details link text like this:

    .dialog-pane > .button-bar > .container > .details-button {
        -fx-text-fill: red;
    }
    

    more or less

    Default styling rules are in modena.css. This answer looked at those then added an additional rule to customize them.

    Login or Signup to reply.
  2. The selector for the is incorrect, for multiple reasons.

    Generally, if you have two selectors separated by whitespace, it will match any node for the second selector which is a descendant node of a node matching the first selector. "Descendant node" for JavaFX typically means nodes that have the other node as a parent, or as a parent of a parent, etc (though there are some exceptions to this).

    So your selector

    .alert_001 .dialog-pane .button-bar .container .details-button .more .text {
       
    }
    

    will match a node with style class text that is a descendant of a node with style class more, that is a descendant of a node with style class details-button, that is a descendant of a node with style class container, etc.

    As you note, the more style class is applied to the hyperlink that also has style class details-button. So there is no node with style class more that is contained in a node with style class details-button (there is just a single node with both style classes).

    Similarly, you add the style class alert_001 to the dialog pane. So there is no node with style class dialog-pane that is contained in a node with style class alert_001 (there is just a single node, the dialog pane, that has both style classes).

    Also note that the .text selector will select the Text node that is used to display the text of the hyperlink. Text nodes do not have a -fx-text-fill property (see the documentation), but have a -fx-fill property that is inherited from Shape.

    If you want to select a single node that matches two different selection nodes, you can concatenate the selection rules with no whitespace. So the following will select a node with both style class dialog-pane and style class alert_001:

    .alert_001.dialog-pane {
        /* ... */
    }
    

    and similarly the selector

    .details-button.more {
        /* ... */
    }
    

    will select a node with both style class details-button and style class more.

    So if you want to be really specific in your CSS, you can select the text in the "more" hyperlink with

    .alert_001.dialog-pane .button-bar .container .details-button.more .text{
        -fx-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    

    I don’t think you need to be this specific (and it usually makes more sense to style the control (i.e. the hyperlink), not its underlying rendering). So I would simply do

    .alert_001 .more {
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    

    if you want to specifically select the expand (but not the collapse) button, or

    .alert_001 .less {
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    

    to style the collapse (but not the expand) button, or

    .alert_001 .details-button {
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    

    to style the button in either state.

    Note also that since the style here is exactly the same as the style you apply to labels in the dialog pane, you can combine these into a single rule:

    .alert_001 .label, .alert_001 .details-button {
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    

    So the following style sheet achieves what I think you want:

    .alert_001 {
        -fx-background-color: #282828;
    }
    
    .alert_001 .header-panel {
        -fx-background-color: #45494a;
    }
    
    .alert_001 .label, .alert_001 .details-button {
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 12.0pt;
    }
    
    .alert_001 .button {
        -fx-border-color: #5e6060;
        -fx-border-radius: 10.0 10.0 10.0 10.0;
        -fx-background-color: #3c3f41;
        -fx-background-radius: 10.0 10.0 10.0 10.0;
        -fx-text-fill: #bbbbbb;
        -fx-font-size: 14.0pt;
    }
    

    The one caveat here is that the details button CSS style class is not documented, so there is no particular guarantee it will continue to work in future JavaFX releases. The JavaFX team do seem to be quite good about preserving back-compatibility in CSS style names (even for undocumented functionality) when releasing new versions, and there is really no other way to get at these elements anyway.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search