JavaFX TableView с выделенным текстом

Я хочу выделить части текста, отображаемые в JavaFXTableView, До сих пор я использую 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
  • Пользователь должен иметь возможность фильтровать этот текст
  • Каждый фрагмент текста, который соответствует текущему поисковому запросу, должен быть выделен.

Теперь у вас есть два варианта:

  1. Создайте HBox и добавьте метки, связанные с фрагментами текста. Метка расширяет область и поэтому может иметь цвет фона.
  2. Используйте 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.

Теперь задача состоит в том, чтобы адаптировать это в вашем методе...

Другие вопросы по тегам