有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

荡秋千。getPreferredSize不总是在Java 9中工作?

这个问题是关于Java 8和Java 9中JEditorPane的不同行为。我想知道其他人是否也经历过同样的情况,这是否可能是Java9中的一个bug,如果可能的话,您可以提供一些关于如何在Java9中处理它的信息

上下文:在我们(古老的)代码库中,我们使用JTable子类,在其中一列中呈现多行HTML时,我们使用JEditorPane子类。我们使用JEditorPane.getPreferredSize()来确定内容的高度,并使用它来设置表行的高度。多年来一直运转良好。它在Java9中不起作用;这些行的显示高度仅为10像素。在Windows和Mac上都可以看到

我想向您展示两个代码示例。如果第一个和较短的就够了,可以跳过第二个和较长的

MCVE:

JEditorPane pane = new JEditorPane("text/html", "");

pane.setText("<html>One line</html>");
System.out.println(pane.getPreferredSize());
pane.setText("<html>Line one<br />Line 2<br />Third line<br />Line four</html>");
System.out.println(pane.getPreferredSize());

Java 8(1.8.0131)中的输出:

java.awt.Dimension[width=48,height=15]
java.awt.Dimension[width=57,height=60]

在Java 9(jdk-9.0.4)上:

java.awt.Dimension[width=49,height=15]
java.awt.Dimension[width=58,height=0]

在Java9中,我第一次设置文本时,首选的高度反映了它。以后每次都不会

我搜索了一下,看看是否能找到任何可能导致这种情况的bug信息,但没有找到任何相关信息

问题:这是有意(改变)行为吗?是虫子吗

更详细的例子

public class TestJEditorPaneAsRenderer extends JFrame {

    public TestJEditorPaneAsRenderer() {
        super("Test JEditorPane");
        
        MyRenderer renderer = new MyRenderer();
        
        String html2 = "<html>one/2<br />two/2</html>";
        String html4 = "<html>one of four<br />two of four<br />"
                + "three of four<br />four of four</html>";
        JTable table = new JTable(new String[][] { { html2 }, { html4 } },
                                  new String[] { "Dummy col title" }) {
            @Override
            public TableCellRenderer getDefaultRenderer(Class<?> colType) {
                return renderer;
            }
        };
        
        add(table);
        setSize(100, 150);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.version"));
        new TestJEditorPaneAsRenderer().setVisible(true);
    }

}

class MyRenderer extends JEditorPane implements TableCellRenderer {

    public MyRenderer() {
        super("text/html", "");
    }
    
    @Override
    public Component getTableCellRendererComponent(
            JTable table, Object value, boolean selected, boolean hasFocus, int row, int col) {
        setText(value.toString());
        Dimension preferredSize = getPreferredSize();
        System.out.format("Row %d preferred size %s%n",row, preferredSize);
        if (preferredSize.height > 0 && table.getRowHeight(row) != preferredSize.height) {
            table.setRowHeight(row, preferredSize.height);
        }
        return this;
    }
    
}

Java 8上的结果与预期一致:

Java 8 screen shot

Java 8的输出:

1.8.0_131
Row 0 preferred size java.awt.Dimension[width=32,height=30]
Row 1 preferred size java.awt.Dimension[width=72,height=60]
Row 0 preferred size java.awt.Dimension[width=32,height=30]
Row 1 preferred size java.awt.Dimension[width=72,height=60]

在Java 9上,第二行显示的高度不够高,因此大多数行是隐藏的:

Java 9 screen shot showing problem

Java 9的输出:

9.0.4
Row 0 preferred size java.awt.Dimension[width=33,height=30]
Row 1 preferred size java.awt.Dimension[width=73,height=0]
Row 0 preferred size java.awt.Dimension[width=33,height=0]
Row 1 preferred size java.awt.Dimension[width=73,height=0]

一个可能的修复方法是,每次通过将getDefaultRenderer()的主体更改为以下内容来创建一个新的渲染器组件:

return new MyRenderer();

现在这个表看起来和Java8上的一样好。如果有必要,我想我们可以在生产代码中使用类似的修复程序,但这似乎是一种浪费。尤其是在行为改变在即将到来的Java版本中恢复之前,这是必要的


共 (1) 个答案

  1. # 1 楼答案

    我也遇到过类似的问题,但都是因为杰拉贝尔。我的解决方案是设置JLabel的大小,这似乎迫使组件重新计算其首选大小

    试试这个:

    JEditorPane pane = new JEditorPane("text/html", "");
    
    pane.setText("<html>One line</html>");
    System.out.println(pane.getPreferredSize());
    pane.setText("<html>Line one<br />Line 2<br />Third line<br />Line four</html>");
    
    // get width from initial preferred size, height should be much larger than necessary
    pane.setSize(61, 1000);
    
    System.out.println(pane.getPreferredSize());
    

    在这种情况下,输出是

    java.awt.Dimension[width=53,height=25]
    java.awt.Dimension[width=61,height=82]
    

    注意:我的字体不同,这就是我得到不同尺寸的原因

    编辑:我在这个较长的示例中更改了GetTableCellRenderer组件,它对我有效。我正在使用jdk9。0.4,64位

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int col) {
        setText(value.toString());
    
        Dimension preferredSize = getPreferredSize();
        setSize(new Dimension(preferredSize.width, 1000));
        preferredSize = getPreferredSize();
    
        System.out.format("Row %d preferred size %s%n", row, preferredSize);
        if (preferredSize.height > 0 && table.getRowHeight(row) != preferredSize.height) {
            table.setRowHeight(row, preferredSize.height);
        }
        return this;
    }