JavaFX TableView with highlighted text

倾然丶 夕夏残阳落幕 提交于 2019-12-12 17:19:35

问题


I want to highlight parts of text displayed in a JavaFX TableView. Till now i'm using Text objects in TextFlow objects. To highlight specific parts in a text i am using tags to cut the text in parts (javafx.scene.text objects) to highlight or not to highlight 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 linebreaks as shown in the picture. The text does not contain any linebreaks.

(Sorry for the picture quality, its a real screenshot :))

Any help is appreciated.

Solution
As @eckig suggested, using multiple Labels in a HBox is an good idea, because each 'Label' can have its own background color and you can use as much Labels in line in a HBox 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;
    }
});

回答1:


After double reading your problem I think we can resume this as follows:

  • A rather long text in a TableColumn
  • The user should be able to filter this text
  • Each text-fragment which matches the current search term is to be highlighted.

Now you have two options:

  1. Create a HBox and add Labels containg the text fragments. A Label extends Region and so may have a background color.
  2. Use TextFlow and add Texts as text fragments. There you can "only" change the foreground color.

Ah and before I forget: To disable TextFlow text wrapping you must not call textModule.setWrappingWidth(Double.MAX_VALUE); but instead textModule.setPrefWidth(Double.MAX_VALUE);

And another hint: Try to recycle as much as possible. Recreating the whole TextFlow on each update is not really a good idea (instead store it as member variable in the cell).




回答2:


According to this, Text doesn't have background stylable properties, so that's why changing -fx-text-background-color doesn't have any effect on it.

One possible workaround for this is wrapping this text node in an HBox, where you can easily set its background to yellow. But this has several drawbacks, such as the textflow losing the ability to manage the content.

If you really need highlighting, other possible solution could be styling the background of the textflow, by finding the bounds of the text, and setting the proper insets.

This is an example I've quickly done with Scenic Builder and some css:

.textflow {
    -fx-background-color: yellow;
    -fx-background-insets: 2 139.3 10 200;
}

I've taken into account the width of the textflow (510) and the widths of the different text nodes using local bounds: 200, 170.7 and 129. So the right inset is 510-200-170.7=139.3 and the left inset is given from the first node width, 200.

Now the challenge is adapt this in your method...



来源:https://stackoverflow.com/questions/26906810/javafx-tableview-with-highlighted-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!