JavaFX 9/10 不再可能覆盖 TableView.resizeColumnToFitContent

Posted

技术标签:

【中文标题】JavaFX 9/10 不再可能覆盖 TableView.resizeColumnToFitContent【英文标题】:JavaFX 9/10 no longer possible to override TableView.resizeColumnToFitContent 【发布时间】:2018-11-08 01:59:19 【问题描述】:

在 JavaFX 8 中,可以覆盖 TableView.resizeColumnToFitContent 函数。这对我们的目的至关重要,因为它允许我们在默认实现之外增强列标题的布局方式,以及在较大的表中调整默认值的性能。

如何增强布局行为的一个例子是在嵌套列标题的上下文中。默认情况下,叶列标题的 prefWidth 根据该列中数据行的最大宽度或叶列标题文本的宽度设置,以较大者为准。但是,如果该叶子标题有一些父列标题具有更宽的标题文本,它们将被剪裁并显示一个省略号。这对我们来说是不可取的,因此我们更改了resizeColumnToFitContent,因此叶列标题的 prefWidth 也考虑了其父列标题的 prefWidth。

从 Java 9 和以下提交开始,resizeColumnToFitContent 函数已移至静态位置,从而无法自定义此行为:

http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/53bfdfed5bbf

大约一周前,我写信给负责此更改的作者 Jonathan Giles,但我猜他是个忙碌的人,这正在成为我们以及我们将产品迁移到 Java 10 的计划的阻碍问题,所以我想我还想看看社区是否知道我可以如何解决这个问题。到目前为止,唯一的选择似乎是有点蛮力的方法outlined here,但也许有更好的方法?

【问题讨论】:

FWIW,乔纳森不再为甲骨文工作。这种方法实际上从来都不是公共 API 的一部分,是吗? James 是对的——我不再在 Oracle 工作,也不再负责那里的任何代码 :-) 我建议你采取蛮力方法——这基本上就是你想要公开的代码所做的无论如何(从记忆中) 为什么这个函数不能成为受保护 API 的一部分? TableView 是 JavaFX 中的核心控件,应该尽可能地扩展,而不必诉诸蛮力。你认为值得我花时间向 OpenJDK 提交 PR 来实现吗? 基本上,继承在某种程度上破坏了封装,因为要覆盖一个方法,您必须了解该方法的实现。这意味着如果 API 允许重写某个方法,那么它将始终将该 API 提交给该特定实现。当皮肤类在 Java 9 中移至公共 API 时,一些方法被设为私有(或移至实用程序类);大概这些是 JavaFX 团队尚未准备好提交所使用的特定实现的方法。如果您还没有,请阅读 Josh Bloch 的“Effective Java”。 James 是对的(再次)——API 设计的最佳方法是缓慢而谨慎。制作一个“尽可能可扩展”的 API 是一件非常困难的事情,因为这意味着我们基本上只是将整个实现公开,这使我们永远无法更改与代码相关的任何内容,因为这意味着我们可能会破坏某人。这就是为什么首先将 API 和实现的概念分开的原因 - 像这里所做的那样依赖实现是不明智的,因为不能保证它会保持稳定。 【参考方案1】:

如果你想重写这个方法,为什么你不实现你自己的 resizeColumnToFitContent 就像在 TableSkinUtils 中那样?

【讨论】:

该方法是从其中一个皮肤类(TableColumnHeader,也许还有其他)中的private 方法调用的,因此您不能覆盖调用它的方法。因此,可能是设计使然,没有办法重新定义这种行为。 (你基本上最终会从头开始重新实现几乎所有的皮肤。) @James_D 确实是这样,有许多相关的类需要重新实现【参考方案2】:

借助 Java 16,我们现在可以以新的方式访问 resizeColumnToFitContent

class FitWidthTableView<T> extends TableView<T> 
    
    public FitWidthTableView() 
        setSkin(new FitWidthTableViewSkin<>(this));
    

    public void resizeColumnsToFitContent() 
        Skin<?> skin = getSkin();
        if (skin instanceof FitWidthTableViewSkin<?> ctvs) ctvs.resizeColumnsToFitContent();
    


class FitWidthTableViewSkin<T> extends TableViewSkin<T> 
    
    public FitWidthTableViewSkin(TableView<T> tableView) 
        super(tableView);
    

    @Override
    protected TableHeaderRow createTableHeaderRow() 
        return new TableHeaderRow(this) 
            
            @Override
            protected NestedTableColumnHeader createRootHeader() 
                return new NestedTableColumnHeader(null) 
                    
                    @Override
                    protected TableColumnHeader createTableColumnHeader(TableColumnBase col) 
                        return new FitWidthTableColumnHeader(col);
                    
                ;
            
        ;
    

    public void resizeColumnsToFitContent() 
        for (TableColumnHeader columnHeader : getTableHeaderRow().getRootHeader().getColumnHeaders()) 
            if (columnHeader instanceof FitWidthTableColumnHeader colHead) colHead.resizeColumnToFitContent(-1);
        
    


class FitWidthTableColumnHeader extends TableColumnHeader 
    
    public FitWidthTableColumnHeader(TableColumnBase col) 
        super(col);
    

    @Override
    public void resizeColumnToFitContent(int rows) 
        super.resizeColumnToFitContent(-1);
    

【讨论】:

以上是关于JavaFX 9/10 不再可能覆盖 TableView.resizeColumnToFitContent的主要内容,如果未能解决你的问题,请参考以下文章

javaFX的几个新特性,让swing彻底过时

JavaFx 缩放和平移覆盖固定比例标签的图像

软件测试作业4

为啥嵌入 UINavigationController 时不再显示 UITableView

UISearchBar 被 tableViewHeader 覆盖

来自 RHEL 的 JavaFX