JavaFX: Apply text color to TableCell using custom style sheet?
Solution 1
As José points out in his answer, if you are setting a graphic in your cell, you (probably) need to apply the css style class to the graphic (depending on what that graphic is). If you are simply calling setText(...)
your code should work.
The reason that a Label
set as the graphic doesn't inherit -fx-text-fill
from the table cell is that the Label
also has a setting for -fx-text-fill
. In the default stylesheet, both TableCell
and Label
have this set as follows:
-fx-text-fill: -fx-text-background-color ;
fx-text-background-color
is a looked-up color that is defined as a ladder, as follows:
-fx-text-background-color: ladder(
-fx-background,
-fx-light-text-color 45%,
-fx-dark-text-color 46%,
-fx-dark-text-color 59%,
-fx-mid-text-color 60%
);
This (fairly complex) setting means that the value of -fx-text-background-color
depends on the value of -fx-background
. If -fx-background
is less than 45% of maximum intensity (i.e. it's dark), the value of -fx-text-background-color
is set to -fx-light-text-color
. If -fx-background
is between 46% and 59% intensity, the value is equal to -fx-drak-text-color
. If it is 60% or more, it's set to -fx-mid-text-color
. The idea here is that the text color will automatically adjust to the background to remain visible. The values of -fx-dark-text-color
, -fx-mid-text-color
, and -fx-light-text-color
are set to black, a dark gray (#333), and white, respectively.
Since Label
does not override the value of -fx-text-background-color
, you can achieve what you need by just changing the value of that for your table cell:
.styleImportant {
-fx-text-background-color: red ;
}
Now this overrides the looked-up color value for the table cell, and since the graphic inside the cell doesn't override that value itself, it inherits it from the cell.
A more sophisticated way to do this is to redefine the -fx-[light|mid|dark]-text-color
s. The advantage of this is that the colors will adjust appropriately if you change the background: in particular if the cell is selected you can ensure that the text stays visible:
.styleImportant {
-fx-light-text-color: white ;
-fx-mid-text-color: #c00 ;
-fx-dark-text-color: red ;
}
Solution 2
Since I don't know what type of object is in the cell, I'll use a Label
.
This is what you are doing:
@Override
public void start(Stage primaryStage) {
TableView<Label> table = new TableView<>();
TableColumn<Label,String> column = new TableColumn<>();
column.setCellValueFactory(param -> param.getValue().textProperty());
column.setCellFactory((TableColumn<Label, String> param) -> {
TableCell<Label, String> cell = new TableCell<Label, String>(){
@Override
protected void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if(!empty){
this.getStyleClass().add("styleImportant");
Label label = new Label(item);
setGraphic(label);
}
}
};
return cell;
});
table.getColumns().add(column);
...
}
This will give you bold text, but black.
If you want to have an object (in my case, a Label
) with red text, apply the style sheet to the object:
@Override
protected void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if(!empty){
Label label = new Label(item);
label.getStyleClass().add("styleImportant");
setGraphic(label);
}
}
EDIT
This is the full code of the example:
@Override
public void start(Stage primaryStage) {
TableView<Label> table = new TableView<>();
ObservableList<Label> data = FXCollections.observableArrayList(
new Label("Some Text"), new Label("Some More Text"));
TableColumn<Label,String> column = new TableColumn<>("Column");
column.setCellValueFactory(param -> param.getValue().textProperty());
column.setCellFactory((TableColumn<Label, String> param) -> {
TableCell<Label, String> cell = new TableCell<Label, String>(){
@Override
protected void updateItem(String value, boolean empty){
super.updateItem(value, empty);
if(!empty){
Label label = new Label(value);
label.getStyleClass().add("styleImportant");
setGraphic(label);
} else {
setGraphic(null);
}
}
};
return cell;
});
column.setPrefWidth(100);
table.getColumns().add(column);
table.setItems(data);
Scene scene = new Scene(table, 300, 250);
scene.getStylesheets().add(getClass().getResource("table.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
where in table.css:
.styleImportant {
-fx-font-weight: bold;
-fx-text-fill: red;
}
Running this short sample should look like this:
Comments
-
user1438038 almost 2 years
JavaFX: How can I apply text color to a TableCell using a custom style sheet?
It works fine, when I use
setTextFill()
in my CellFactory directly, but I want to apply custom style using an external CSS file. I could prove that my CSS class is applied, since the font becomes bold. The CSS file's font color, however, is not applied.@Override protected void updateItem(MyObject item, boolean empty) { super.updateItem(item, empty); if (null != item) { // EITHER: this.getStyleClass().add("styleImportant"); // Does NOT set color. // OR: this.setTextFill(Color.RED); // Does set color. } else { this.getStyleClass().remove("styleImportant"); } }
Style sheet:
.styleImportant { -fx-font-weight: bold; /** Does work. */ -fx-text-fill: red; /** Does NOT work. */ }
It is somehow related to specificity of CSS selectors, but I did not manage to find any valid setup.
Edit: I managed to apply both, a custom text color and background color, using CSS. My implementation now uses a
Label
that is wrapped in aVBox
to make the background color fill the entire table cell. However, I still had some issues with background color not being cleared when removing the custom style.Is there any better solution than applying a clear style?
colExample.setCellFactory(new Callback<TableColumn<Example, Example>, TableCell<Example, Example>>() { @Override public TableCell<Example, Example> call(TableColumn<Example, Example> tableColumn) { return new TableCell<Example, Example>() { private VBox container; private Label text; // Anonymous constructor { this.container = new VBox(); this.text = this.createLabel(); this.container.getChildren().add(this.text); this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); this.setStyle("-fx-padding: -1 -1 -1 -1;"); // Remove padding from cell this.setGraphic(this.container); } private final Label createLabel() { Label label = new Label(); VBox.setVgrow(label, Priority.ALWAYS); label.setMaxWidth(Double.MAX_VALUE); label.setMaxHeight(Double.MAX_VALUE); label.setAlignment(Pos.CENTER); return label; } @Override protected void updateItem(Example example, boolean empty) { super.updateItem(example, empty); // Reset column styles if (null != this.text && null != this.text.getStyleClass()) { String[] possibleStyles = new String[] { "styleImportant", "clearStyle" }; for (String style: possibleStyles) { if (this.text.getStyleClass().contains(style)) { // Will not reset background, even though style is removed? this.text.getStyleClass().remove(style); } } // Apply reset style to clear background color this.text.getStyleClass().add("clearStyle"); } if (null != example) { this.text.setText(example.getContent()); if (example.isImportant()) { this.text.getStyleClass().add("styleImportant"); } } } }; } });
My style sheet:
/** Keep black text color, when user selects row */ .table-row-cell:focused { -fx-dark-text-color: #000000; -fx-mid-text-color: #000000; -fx-light-text-color: #000000; } /** Style to reset background color */ .clearStyle { -fx-background-color: transparent; } /** Style for important cells */ .styleImportant { /** Red text color on any background */ -fx-dark-text-color: #FF0000; -fx-mid-text-color: #FF0000; -fx-light-text-color: #FF0000; -fx-background-color: #FF9999; }
-
user1438038 over 9 yearsUnfortunately, none of this works for me. Neither when using
setText()
, nor when I add aLabel
and apply my style class to it. All I get is bold, but never colored text. Furthermore, I ran into issues with background color nor filling entire cell, when using a label. -
José Pereda over 9 yearsI've edited my answer, adding the full code of my example. Try to run it and see it works for you. Then fix your project accordingly. If still it doesn't work, update your question with the details necessary for us to reproduce your error.
-
user1438038 over 9 yearsThank you. I had
.table-row-cell:focused .text { -fx-fill: #000000; }
set to have black font, when user selects a table row. That seems to interfer with my custom style. The information @James_D gave is very helpful in that respect, but I'm still figuring out... I'll get back to you, as soon as I fixed my issues. -
user1438038 over 9 yearsUpdated my question, I'm using a
Label
andVBox
now. Works for me now, except for some issues I had with resetting the cell's background color. -
user1438038 over 9 yearsThank you @James_D, you provided very useful information. I've updated my question to show my current implementation. The way I defined
.table-row-cell:focused .text
was interfering with the custom style. Now that I set-fx-[light|mid|dark]-text-color
, it is working. I had some issues with resetting the background color, though. -
user1438038 over 9 yearsThough it did not solve my problem directly, I will accept your answer. You provided valuable information that helped me the most and finally made me master this issue. Thank you.