JEdi​​torPane.getPreferredSize并不总是在Java 9中工作?

Ole*_*.V. 10 java swing jeditorpane preferredsize java-9

这个问题是关于JEditorPaneJava 8和Java 9中的不同行为.我想知道其他人是否经历过相同的事情,是否它可能是Java 9中的一个错误,如果可能的话,你有如何在Java中处理它的输入9.

上下文:在我们(古老的)代码库中,我们使用的是子类JTable,并且在我们使用的子类之一的列中呈现多行HTML JEditorPane.我们JEditorPane.getPreferredSize()用于确定内容的高度并使用它来设置表格行的高度.它已经运作了很多年.它在Java 9中不起作用; 行显示只有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());
Run Code Online (Sandbox Code Playgroud)

Java 8(1.8.0_131)中的输出:

java.awt.Dimension[width=48,height=15]
java.awt.Dimension[width=57,height=60]
Run Code Online (Sandbox Code Playgroud)

在Java 9(jdk-9.0.4)上:

java.awt.Dimension[width=49,height=15]
java.awt.Dimension[width=58,height=0]
Run Code Online (Sandbox Code Playgroud)

在Java 9中,我第一次设置文本时,首选高度反映了它.以后每次都没有.

我已经搜索过,看看我是否能找到任何可能导致此问题的错误信息,但没有发现任何相关内容.

问题:这是否意图(改变)行为?这是一个错误?

更长的例子

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

Java 8的结果如预期:

Java 8屏幕截图

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]
Run Code Online (Sandbox Code Playgroud)

在Java 9上,第二行未显示得足够高,因此大多数行都被隐藏:

Java 9屏幕截图显示问题

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]
Run Code Online (Sandbox Code Playgroud)

可能的解决方法是每次通过更改getDefaultRenderer()to 的主体来创建新的渲染器组件

            return new MyRenderer();
Run Code Online (Sandbox Code Playgroud)

现在这个表在Java 8上看起来很好.如果有必要,我想我们可以在生产代码中使用类似的修复程序,但这似乎很浪费.特别是如果只有在将来的Java版本中恢复行为更改之前才需要它.我很感激你的建议.

Mat*_*heM 8

我遇到过类似的问题,但是有了JLabel.我的解决方案是设置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());
Run Code Online (Sandbox Code Playgroud)

在这个casse输出是

java.awt.Dimension[width=53,height=25]
java.awt.Dimension[width=61,height=82]
Run Code Online (Sandbox Code Playgroud)

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

编辑:我在更长的例子中改变了你的getTableCellRendererComponent,这对我有用.我使用的是64位的jdk9.0.4.

@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;
}
Run Code Online (Sandbox Code Playgroud)

  • @Holger我尝试了`invalidate();`,`validate();`,`revalidate()`的各种组合,......并没有改变首选高度.我认为设置组件的大小是这个黑客的重要组成部分.我还发现用`setHeight`设置的高度不一定要大,只需要大于初始首选高度. (2认同)