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.

scrennshot oft table

(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;
    }
});

      

+3


source to share


2 answers


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).

+3


source


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;
}

      

Highlighted text

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 ...

+2


source







All Articles