Java 如何仅在文本被省略(…)的表格单元格上显示工具提示?

Java 如何仅在文本被省略(…)的表格单元格上显示工具提示?,java,javafx,Java,Javafx,要创建工具提示,我使用以下基于此的代码 回调existingCellFactory=column.getCellFactory(); 列。setCellFactory(c->{ TableCell cell=existingCellFactory.call((TableColumn)c); 工具提示工具提示=新工具提示(); tooltip.textProperty().bind(cell.textProperty()); cell.tooltipProperty().bind( Binding

要创建工具提示,我使用以下基于此的代码

回调existingCellFactory=column.getCellFactory(); 列。setCellFactory(c->{ TableCell cell=existingCellFactory.call((TableColumn)c); 工具提示工具提示=新工具提示(); tooltip.textProperty().bind(cell.textProperty()); cell.tooltipProperty().bind( Bindings.when(Bindings.or(cell.e‌mptyProperty(),cell.itemProperty().isNull()) 。然后((工具提示)null)。否则(工具提示)); 返回单元; }); 问题是,在这种情况下,当用户在表格上移动鼠标时,任何单元格上的工具提示都会出现,并且用户会得到太多的工具提示


如何仅在表格单元格上显示工具提示,这些单元格的文本宽度更宽,并在末尾替换为“…”

以下是我解决这个问题的尝试。

注意:我使用的是基于的
com.sun.javafx.scene.control.skin.Utils。有些方法似乎被低估了。此答案假设您使用的是默认字体。

此应用程序检查表格中的每个表格单元格,并确定单元格内的文本是否被省略。它使用了
JavaFx
实用程序

主要

此实用程序类应按发布的方式工作。我从类中删除了一些方法以满足此站点角色约束。我从学校得到了实用课程


这应该可以解决您的问题

column.setCellFactory(col -> new TableCell<Object, String>()
{
    @Override
    protected void updateItem(final String item, final boolean empty)
    {
        super.updateItem(item, empty);
        setText(item);
        TableColumn tableCol = (TableColumn) col;

        if (item != null && tableCol.getWidth() < new Text(item + "  ").getLayoutBounds().getWidth())
        {
            tooltipProperty().bind(Bindings.when(Bindings.or(emptyProperty(), itemProperty().isNull())).then((Tooltip) null).otherwise(new Tooltip(item)));
        } else
        {
            tooltipProperty().bind(Bindings.when(Bindings.or(emptyProperty(), itemProperty().isNull())).then((Tooltip) null).otherwise((Tooltip) null));
        }

    }
});
column.setCellFactory(col->newtableCell()
{
@凌驾
受保护的void updateItem(最终字符串项,最终布尔值为空)
{
super.updateItem(项,空);
setText(项目);
TableColumn tableCol=(TableColumn)col;
if(item!=null&&tableCol.getWidth()
的可能重复项的可能重复项。感谢您的代码,但我在其中没有看到任何工具提示。我之所以这样做是因为答案已作为重复项关闭。这只是试图确定单元格是否为椭圆。您可以将其合并到工具提示代码中。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
 *
 * @author Sedrick
 */
public class JavaFXApplication5 extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
            FXCollections.observableArrayList(new Person("A", "B"), new Person("ZZZZZZZZZZZZZZZZ","XXXXXXXXXXXXXXXX"), new Person("ZZZ", "XXX"));
    final HBox hb = new HBox();

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

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setWidth(450);
        stage.setHeight(550);


        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<>("firstName"));

        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol);

        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {
            data.add(new Person("ZZZZZZZZZZZZZZZZ","XXXXXXXXXXXXXXXX"));
            data.add(new Person("ZZZ", "XXX"));
         });

        hb.getChildren().addAll(addButton);
        hb.setSpacing(3);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(table, hb);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
        //ScenicView.show(scene);

        //loop through all the table cells
        for(TableColumn tableColumn : table.getColumns())
        {
            for(int i = 0; i < table.getItems().size(); i++)
            {                
                System.out.println(tableColumn.getCellData(i) + " isCellEllipsized: " + isCellEllipsized(tableColumn.getWidth(), tableColumn.getCellData(i).toString()));
            }
        }
    }

    boolean isCellEllipsized(double tableColumnWidth, String cellData)
    {
        Text text = new Text(cellData);//Convert String to Text
        double textActualWidth = text.getBoundsInLocal().getWidth();//Get the width of the Text object
        double textComputedWidth = Utility.computeTextWidth(text.getFont(), cellData, tableColumnWidth);//Use the utility. It returns how long the text should be if it needs to be ellipsized and the actual text lengh if it does not need to be ellipsized.

        return textActualWidth > textComputedWidth;
    }
    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;

        private Person(String fName, String lName) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }
    }
} 
/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


import java.text.Bidi;
import java.text.BreakIterator;

import static javafx.scene.control.OverrunStyle.*;
import javafx.application.Platform;
import javafx.application.ConditionalFeature;
import javafx.geometry.Bounds;
import javafx.geometry.HPos;
import javafx.geometry.Point2D;
import javafx.geometry.VPos;
import javafx.scene.control.OverrunStyle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;

import com.sun.javafx.scene.text.HitInfo;
import com.sun.javafx.scene.text.TextLayout;
import com.sun.javafx.tk.Toolkit;

/**
 * BE REALLY CAREFUL WITH RESTORING OR RESETTING STATE OF helper NODE AS LEFTOVER
 * STATE CAUSES REALLY ODD NASTY BUGS!
 *
 * We expect all methods to set the Font property of helper but other than that
 * any properties set should be restored to defaults.
 */
public class Utility {

    static final Text helper = new Text();
    static final double DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
    static final double DEFAULT_LINE_SPACING = helper.getLineSpacing();
    static final String DEFAULT_TEXT = helper.getText();
    static final TextBoundsType DEFAULT_BOUNDS_TYPE = helper
            .getBoundsType();

    /* Using TextLayout directly for simple text measurement.
     * Instead of restoring the TextLayout attributes to default values
     * (each renders the TextLayout unable to efficiently cache layout data).
     * It always sets all the attributes pertinent to calculation being performed.
     * Note that lineSpacing and boundsType are important when computing the height
     * but irrelevant when computing the width.
     *
     * Note: This code assumes that TextBoundsType#VISUAL is never used by controls.
     * */
    static final TextLayout layout = Toolkit.getToolkit()
            .getTextLayoutFactory().createLayout();

    static double getAscent(Font font, TextBoundsType boundsType) {
        layout.setContent("", font.impl_getNativeFont());
        layout.setWrapWidth(0);
        layout.setLineSpacing(0);
        if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
            layout.setBoundsType(TextLayout.BOUNDS_CENTER);
        } else {
            layout.setBoundsType(0);
        }
        return -layout.getBounds().getMinY();
    }

    static double getLineHeight(Font font, TextBoundsType boundsType) {
        layout.setContent("", font.impl_getNativeFont());
        layout.setWrapWidth(0);
        layout.setLineSpacing(0);
        if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
            layout.setBoundsType(TextLayout.BOUNDS_CENTER);
        } else {
            layout.setBoundsType(0);
        }
        return layout.getBounds().getHeight();
    }

    static double computeTextWidth(Font font, String text,
            double wrappingWidth) {
        layout.setContent(text != null ? text : "",
                font.impl_getNativeFont());
        layout.setWrapWidth((float) wrappingWidth);
        return layout.getBounds().getWidth();
    }    
}
column.setCellFactory(col -> new TableCell<Object, String>()
{
    @Override
    protected void updateItem(final String item, final boolean empty)
    {
        super.updateItem(item, empty);
        setText(item);
        TableColumn tableCol = (TableColumn) col;

        if (item != null && tableCol.getWidth() < new Text(item + "  ").getLayoutBounds().getWidth())
        {
            tooltipProperty().bind(Bindings.when(Bindings.or(emptyProperty(), itemProperty().isNull())).then((Tooltip) null).otherwise(new Tooltip(item)));
        } else
        {
            tooltipProperty().bind(Bindings.when(Bindings.or(emptyProperty(), itemProperty().isNull())).then((Tooltip) null).otherwise((Tooltip) null));
        }

    }
});