Reputation: 111
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.
Upvotes: 0
Views: 1272
Reputation: 209724
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:
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.
Upvotes: 1