JavaFX TableView с выделенным текстом
Я хочу выделить части текста, отображаемые в JavaFX
TableView
, До сих пор я использую Text
объекты в TextFlow
объекты. Чтобы выделить отдельные части в тексте, я использую теги, чтобы разрезать текст на части (javafx.scene.text
объекты) выделять или не выделять с помощью следующего кода.
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;
}
});
К сожалению, подсветка фона не работает, и у меня есть странные разрывы строк, как показано на рисунке. Текст не содержит разрывов строк.
(Извините за качество картинки, это настоящий скриншот:))
Любая помощь приветствуется.
Решение
Как предложил @eckig, используя несколько Labels
в HBox
это хорошая идея, потому что каждая метка может иметь свой собственный цвет фона, и вы можете использовать как можно больше Labels
в очереди в HBox
по мере необходимости:
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;
}
});
2 ответа
После прочтения вашей проблемы, я думаю, мы можем возобновить это следующим образом:
- Довольно длинный текст в TableColumn
- Пользователь должен иметь возможность фильтровать этот текст
- Каждый фрагмент текста, который соответствует текущему поисковому запросу, должен быть выделен.
Теперь у вас есть два варианта:
- Создайте HBox и добавьте метки, связанные с фрагментами текста. Метка расширяет область и поэтому может иметь цвет фона.
- Используйте TextFlow и добавляйте тексты как фрагменты текста. Там вы можете "только" изменить цвет переднего плана.
Ну и прежде чем я забуду: чтобы отключить TextFlow обтекание текста не должны вызывать textModule.setWrappingWidth(Double.MAX_VALUE);
но вместо этого textModule.setPrefWidth(Double.MAX_VALUE);
И еще один совет: старайтесь утилизировать как можно больше. Воссоздание всего TextFlow при каждом обновлении не очень хорошая идея (вместо этого сохраните его как переменную-член в ячейке).
Согласно этому, Text
не имеет фоновых свойств, поэтому меняю -fx-text-background-color
не имеет никакого влияния на это.
Одним из возможных путей решения этой проблемы является обертывание этого текстового узла в HBox
где вы можете легко установить его фон в желтый. Но у этого есть несколько недостатков, таких как поток текста, теряющий способность управлять контентом.
Если вам действительно нужна подсветка, другим возможным решением может быть стилизация фона текстового потока, нахождение границ текста и установка правильных вставок.
Вот пример, который я быстро сделал с Scenic Builder и некоторыми CSS:
.textflow {
-fx-background-color: yellow;
-fx-background-insets: 2 139.3 10 200;
}
Я принял во внимание ширину текстового потока (510) и ширину различных текстовых узлов, используя локальные границы: 200, 170.7 и 129. Таким образом, правая вставка равна 510-200-170.7=139,3, а левая вставка задается от ширины первого узла 200.
Теперь задача состоит в том, чтобы адаптировать это в вашем методе...