JavaFX TableView with selected text
I want to highlight the parts of the text displayed in JavaFX
TableView
. So far, I am using Text
objects in objects TextFlow
. To highlight certain parts of the text, I use tags to cut the text in parts ( javafx.scene.text
objects) to select or not select with the following code.
col3.setCellValueFactory(new PropertyValueFactory<RegexMatch, String>("text"));
col3.setCellFactory(new Callback<TableColumn, TableCell>() {
@Override
public TableCell call(TableColumn param) {
TableCell cell = new TableCell() {
@Override
protected void updateItem(Object text, boolean empty) {
if (text != null && text instanceof String) {
String str = (String) text;
TextFlow flow = new TextFlow();
if (txtSearchField.getText().length() > 3 && str.contains(HIGHLIGHT_START)) {
// Something to highlight
flow.getChildren().clear();
while (str.contains(HIGHLIGHT_START)) {
// First part
Text starttext = new Text(str.substring(0, str.indexOf(HIGHLIGHT_START)));
starttext.setWrappingWidth(Double.MAX_VALUE);
flow.getChildren().add(starttext);
str = str.substring(str.indexOf(HIGHLIGHT_START) + HIGHLIGHT_START.length(), str.length());
// Part to highlight
Text highlightedText = new Text(str.substring(0, str.indexOf(HIGHLIGHT_END)));
highlightedText.setStyle("-fx-text-background-color: yellow;");
highlightedText.setFill(Color.BLUE);
highlightedText.setWrappingWidth(Double.MAX_VALUE);
flow.getChildren().add(highlightedText);
// Last part
str = str.substring(str.indexOf(HIGHLIGHT_END) + HIGHLIGHT_END.length(), str.length());
if (!str.contains(HIGHLIGHT_START)) {
Text endtext = new Text(str);
endtext.setWrappingWidth(Double.MAX_VALUE);
flow.getChildren().add(endtext);
}
}
}else if (txtSearchField.getText().length() < 1) {
// Remove former highlightings and show simple text
str = str.replaceAll(HIGHLIGHT_START, "");
str = str.replaceAll(HIGHLIGHT_END, "");
flow.getChildren().clear();
Text textModule = new Text(str);
textModule.setWrappingWidth(Double.MAX_VALUE);
flow.getChildren().add(textModule);
} else {
// show simple text
flow.getChildren().clear();
Text textModule = new Text(str);
textModule.setWrappingWidth(Double.MAX_VALUE);
flow.getChildren().add(textModule);
}
flow.setPrefHeight(bigIcons ? BIG_SIZE : SMALL_SIZE);
setGraphic(flow);
}
}
};
return cell;
}
});
Unfortunately the background highlighting does not work and I have strange lines as shown in the picture. The text contains no lines.
(Sorry for the image quality, its a real screenshot :))
Any help is appreciated.
Solution
As @eckig suggested, using multiple Labels
in HBox
is a good idea, since each "label" can have its own background color, and you can use as many Labels
in a line as needed:
col3.setCellValueFactory(new PropertyValueFactory<RegexMatch, String("excerptLineTable"));
col3.setCellFactory(new Callback<TableColumn, TableCell>() {
@Override
public TableCell call(TableColumn param) {
TableCell cell = new TableCell() {
@Override
protected void updateItem(Object text, boolean empty) {
if (text != null && text instanceof String) {
HBox hbox = new HBox();
String str = (String) text;
if (txtSearchField.getText().length() > 3 && str.contains(HIGHLIGHT_START)) {
// Something to highlight
hbox.getChildren().clear();
while (str.contains(HIGHLIGHT_START)) {
// First part
Label label = new Label(str.substring(0, str.indexOf(HIGHLIGHT_START)));
hbox.getChildren().add(label);
str = str.substring(str.indexOf(HIGHLIGHT_START) + HIGHLIGHT_START.length(), str.length());
// Part to highlight
Label label2 = new Label(str.substring(0, str.indexOf(HIGHLIGHT_END)));
label2.setStyle("-fx-background-color: blue;");
hbox.getChildren().add(label2);
// Last part
str = str.substring(str.indexOf(HIGHLIGHT_END) + HIGHLIGHT_END.length(), str.length());
if (!str.contains(HIGHLIGHT_START)) {
Label label3 = new Label(str);
hbox.getChildren().add(label3);
}
}
} else if (txtSearchField.getText().length() < 1) {
// Remove former highlightings and show simple text
str = str.replaceAll(HIGHLIGHT_START, "");
str = str.replaceAll(HIGHLIGHT_END, "");
hbox.getChildren().clear();
Label label = new Label(str);
hbox.getChildren().add(label);
} else {
// show simple text
hbox.getChildren().clear();
Label label = new Label(str);
hbox.getChildren().add(label);
}
setGraphic(hbox);
}
}
};
return cell;
}
});
source to share
After reading your problem twice, I think we can resume this like this:
- Quite long text in TableColumn
- The user should be able to filter this text
- Each piece of text that matches the current search query should be highlighted.
You now have two options:
- Create an HBox and add shortcuts containing text snippets. The label expands the area and therefore may have a background color.
- Use TextFlow and add texts as text snippets. There you can "only" change the foreground color.
Ah and before I forget: to disable the TextFlow wrapper you shouldn't call textModule.setWrappingWidth(Double.MAX_VALUE);
, but insteadtextModule.setPrefWidth(Double.MAX_VALUE);
And one more hint: try to rework as much as possible. Playing the entire TextFlow for each update is actually not a good idea (store it as a member variable in the cell instead).
source to share
According to this , Text
has no background styled properties, so that's why the change -fx-text-background-color
has no effect on it.
One possible workaround for this is to wrap this node text in HBox
, where you can easily set its background to yellow. But this has several disadvantages, such as the text stream losing the ability to manipulate the content.
If you really need to highlight, another possible solution would be to style the background of the text flow, find the text boundaries, and set the correct inserts.
This is an example I quickly followed with Scenic Builder and some css:
.textflow {
-fx-background-color: yellow;
-fx-background-insets: 2 139.3 10 200;
}
I took into account the width of the text stream (510) and the widths of the various text nodes using the local borders: 200, 170.7 and 129. So, the right insert is 510-200-170.7 = 139.3, and the left insert is from the first node width , 200.
Now the challenge is to adapt this in your method ...
source to share