Как динамически установить всплывающую подсказку ТОЛЬКО для усеченной ячейки - PullRequest
3 голосов
/ 29 мая 2020

Моя цель - отображать всплывающую подсказку в ячейках, где текст усекается при запуске, но также и во время выполнения , что означает, что при изменении размера столбца всплывающая подсказка может появиться или исчезнуть.

В моей фабрике ячеек я думал, что будет свойство, которое я мог бы привязать или прослушать, и просто связать всплывающую подсказку с ним, но я не нашел.

Вот мой код, который устанавливает всплывающая подсказка на каждой ячейке в cell factory:

public void updateItem(T item, boolean empty) {
    super.updateItem(item, empty);

    if (empty || item == null) {
        setText(null);
        setGraphic(null);
    } else {
        setText(adapter.getCellContentParser().toString(item));
        setTooltip(new Tooltip(this.getText());
    }
}

Обратите внимание , что я ищу все возможные решения на сайте, например эти: { ссылка } =

Как показать всплывающую подсказку только для тех ячеек таблицы, текст которых имеет многоточие (...)?

И они совершенно нормально, когда вы запускаете свою программу, но не работает, когда вы изменяете размер столбцов .

Что-то мне не хватает? Мне это действительно странно что для такого рода вещей не существует наблюдаемых свойств.

1 Ответ

4 голосов
/ 29 мая 2020

Это немного похоже на взлом, но вы можете получить дочерний узел Text в ячейке, выполнив поиск в графе сцены под ячейкой после выполнения макета, а затем создать привязку для всплывающей подсказки, которая проверяет, есть ли у ячейки текст такой же, как и текст текста. Обратите внимание, что мы игнорируем любые графы c, установленные для ячейки здесь, поэтому выполняется поиск только узла Text, отображающего свойство text ячейки:

setCellFactory(tc -> new TableCell<>() {
    private Text text ;
    private Tooltip tooltip = new Tooltip() ;

    {
        tooltip.textProperty().bind(textProperty());
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);

        if (item == null || empty) {
            setText("");
        } else {
            setText(item);
        }
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren();
        if (text == null) {
            text = findTextNode(this);
            bindTooltip();
        }               
    }

    private void bindTooltip() {
        tooltipProperty().bind(Bindings.createObjectBinding(() -> {
            if (getItem()==null) return null ;
            if (getText().equals(text.getText())) return null ;
            return tooltip ;
        }, text.textProperty(), itemProperty(), textProperty()));
    }

    // recursively search through child node graph to find the Text node
    private Text findTextNode(Node root) {
        // Ignore the graphic and all its child nodes:
        if (root == getGraphic()) {
            return null ;
        }
        if (root instanceof Text) {
            return (Text) root ;
        }
        if (root instanceof Parent) {
            for (Node node : ((Parent)root).getChildrenUnmodifiable()) {
                Text text = findTextNode(node);
                if (text != null) return text ;
            }
        }
        return null ;
    }
});

Вот полный рабочий пример:

import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {

    @Override
    public void start(Stage stage) {

        var table = new TableView<Item>();
        var itemCol = column("Item", Item::nameProperty);
        var valueCol = column("Value", Item::valueProperty);
        table.getColumns().add(itemCol);
        table.getColumns().add(valueCol);

        itemCol.setCellFactory(tc -> new TableCell<>() {
            private Text text ;
            private Tooltip tooltip = new Tooltip() ;

            {
                tooltip.textProperty().bind(textProperty());
            }

            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);

                if (item == null || empty) {
                    setText("");
                } else {
                    setText(item);
                }
            }

            @Override
            protected void layoutChildren() {
                super.layoutChildren();
                if (text == null) {
                    text = findTextNode(this);
                    bindTooltip();
                }               
            }

            private void bindTooltip() {
                tooltipProperty().bind(Bindings.createObjectBinding(() -> {
                    if (getItem()==null) return null ;
                    if (getText().equals(text.getText())) return null ;
                    return tooltip ;
                }, text.textProperty(), itemProperty(), textProperty()));
            }

            // recursively search through child node graph to find the Text node
            private Text findTextNode(Node root) {
                // Ignore the graphic and all its child nodes:
                if (root == getGraphic()) {
                    return null ;
                }
                if (root instanceof Text) {
                    return (Text) root ;
                }
                if (root instanceof Parent) {
                    for (Node node : ((Parent)root).getChildrenUnmodifiable()) {
                        Text text = findTextNode(node);
                        if (text != null) return text ;
                    }
                }
                return null ;
            }
        });

        var rng = new Random();
        for (int i = 1 ; i <= 40 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(100)));
        }

        var scene = new Scene(new BorderPane(table));
        stage.setScene(scene);
        stage.show();
    }

    public static <S,T>  TableColumn<S,T> column(String title, Function<S, Property<T>> prop) {
        TableColumn<S,T> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        return col ;
    }

    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();
        public Item(String name, int value) {
            this.name.set(name);
            this.value.set(value);
        }

        public final StringProperty nameProperty() {
            return name ;
        }

        public final IntegerProperty valueProperty() {
            return value ;
        }
    }

    public static void main(String[] args) {
        launch();
    }

}
...