0

I am trying to implement dark mode functionality. For that purpose I need to change the color of treeView to dark grey. The following code is not working.

treeView.setStyle("-fx-background-color:#242424;");

I am not using CSS separately. So solution like the above code will be highly appreciated.

3
  • “Theming” an application (I.e. setting colour schemes that apply to the entire application) is much easier if you use an external style sheet. This can basically be accomplished in less than 10 lines of CSS code. Why do you want to do this without an external CSS file? Commented Jun 13, 2020 at 14:27
  • i haven't used FXML and external css files anywhere in my application so just to remain consistent i don't want to use external css. but still i am ok to use it if it is easier. @James_D Commented Jun 13, 2020 at 16:53
  • An external CSS file is the supported way to theme things - I would recommend doing that. But your code should probably work (I think): you should create a minimal reproducible example that demonstrates the issue. Commented Jun 13, 2020 at 16:55

1 Answer 1

1

You need to change the background colors of the cells. Doing this in Java code is tricky, because it forces you to use a custom cellFactory on the tree to access the cells. Instead, I recommend using an external style sheet. You can do

.tree-cell {
    -fx-background-color:#242424;
}

By default, the background of a tree cell (and many other controls) is set to a "looked-up color" (essentially a CSS variable) called -fx-background. The text in the tree cell (and again, in many other controls) is set to a color dependent on that value, so it will automatically become a light color if the background is dark (and vice-versa). So it's probably better to do

.tree-cell {
    -fx-background:#242424;
}

In general, for "theming" your application, the default stylesheet modena.css defines all colors in terms of a small collection of looked-up colors. Those colors, and their defaults, are

/* A light grey that is the base color for objects.  Instead of using
 * -fx-base directly, the sections in this file will typically use -fx-color.
 */
-fx-base: #ececec;


/* A very light grey used for the background of windows.  See also
 * -fx-text-background-color, which should be used as the -fx-text-fill
 * value for text painted on top of backgrounds colored with -fx-background.
 */
-fx-background: derive(-fx-base,26.4%);

/* Used for the inside of text boxes, password boxes, lists, trees, and
 * tables.  See also -fx-text-inner-color, which should be used as the
 * -fx-text-fill value for text painted on top of backgrounds colored
 * with -fx-control-inner-background.
 */
-fx-control-inner-background: derive(-fx-base,80%);
/* Version of -fx-control-inner-background for alternative rows */
-fx-control-inner-background-alt: derive(-fx-control-inner-background,-2%);

/* A bright blue for highlighting/accenting objects.  For example: selected
 * text; selected items in menus, lists, trees, and tables; progress bars */
-fx-accent: #0096C9;

/* Default buttons color, this is similar to accent but more subtle */
-fx-default-button: #ABD8ED;

/* A bright blue for the focus indicator of objects. Typically used as the
 * first color in -fx-background-color for the "focused" pseudo-class. Also
 * typically used with insets of -1.4 to provide a glowing effect.
 */
-fx-focus-color: #039ED3;
-fx-faint-focus-color: #039ED322;

So a good strategy for "theming" your entire application is to change the definitions of some of these and apply it to the root of the scene. For example, a "dark mode" might be implemented just with

.root {
  -fx-base: #242424 ;
  -fx-control-inner-background: derive(-fx-base,20%);
  -fx-control-inner-background-alt: derive(-fx-control-inner-background,-10%);
  -fx-accent: #006689;
  -fx-focus-color: #036E83;
  -fx-faint-focus-color: #036E8322;
}

Here's a complete example:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {


    @Override
    public void start(Stage stage) {

        TreeView<String> tree = createRandomTree();
        BorderPane root = new BorderPane(tree);

        HBox controls = new HBox(5,
            new Button("Click"),
            new Label("Choose one:"),
            new ComboBox<>(FXCollections.observableArrayList("One", "Two", "Three")),
            new TextField()
        );
        controls.setAlignment(Pos.CENTER);
        controls.setPadding(new Insets(5));
        root.setTop(controls);

        ListView<String> list = new ListView<>();
        IntStream.range(1, 51).mapToObj(i -> "Item "+i).forEach(list.getItems()::add);
        root.setLeft(list);


        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("darkmode.css").toExternalForm());

        stage.setScene(scene);
        stage.show();
    }



    private TreeView<String> createRandomTree() {
        Random rng = new Random();
        List<TreeItem<String>> items = new ArrayList<>();
        TreeItem<String> root = new TreeItem<>("Item 1");
        root.setExpanded(true);
        items.add(root);
        TreeView<String> tree = new TreeView<>(root);
        for (int i = 2 ; i <=20 ; i++) {
            TreeItem<String> item = new TreeItem<>("Item "+i);
            item.setExpanded(true);
            items.get(rng.nextInt(items.size())).getChildren().add(item);
            items.add(item);
        }
        return tree ;
    }



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

}

Where darkmode.css is the CSS file above. This gives:

enter image description here

Note that if you really want to do this without an external CSS file, you can just set those inline styles directly on your root node:

Pane root = ... ;

root.setStyle(
        "  -fx-base: #242424 ;\n" + 
        "  -fx-control-inner-background: derive(-fx-base,20%);\n" + 
        "  -fx-control-inner-background-alt: derive(-fx-control-inner-background,-10%);\n" + 
        "  -fx-accent: #006689;\n" + 
        "  -fx-focus-color: #036E83;\n" + 
        "  -fx-faint-focus-color: #036E8322;");

And you could even just set them for a TreeView, which would apply them only to the tree:

TreeView<String> tree = new TreeView<>();

tree.setStyle(
        "  -fx-base: #242424 ;\n" + 
        "  -fx-control-inner-background: derive(-fx-base,20%);\n" + 
        "  -fx-control-inner-background-alt: derive(-fx-control-inner-background,-10%);\n" + 
        "  -fx-accent: #006689;\n" + 
        "  -fx-focus-color: #036E83;\n" + 
        "  -fx-faint-focus-color: #036E8322;");

but generally, using and external style sheet is better in a number of ways.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.