JEditorPane.getPreferredSize 并不总是在 Java 9 工作?
JEditorPane.getPreferredSize not always working in Java 9?
这个问题是关于 JEditorPane
在 Java 8 和 Java 9 中的不同行为。我想知道其他人是否有过同样的经历,是否可以Java 9 中的错误,如果可能,请在 Java 9 中输入您的意见来处理它。
上下文:在我们的(古老的)代码库中,我们使用 JTable
的子类,为了在其中一列中呈现多行 HTML,我们使用的是 HTML 的子类JEditorPane
。我们使用 JEditorPane.getPreferredSize()
来确定内容的高度,并使用它来设置 table 行的高度。多年来一直运作良好。在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());
Java8 中的输出(1.8.0_131):
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]
在Java 9 我第一次设置文字时,首选高度反映了它。以后每次都不会。
我已经搜索过是否可以找到有关可能导致此问题的错误的任何信息,但没有找到任何相关信息。
问题:这是预期的(改变)行为吗?是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 的输出:
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 的输出:
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();
现在 table 看起来和 Java 8 上的一样好。如果有必要,我想我们可以在生产代码中使用类似的修复程序,但这似乎是一种浪费。特别是如果只有在即将到来的 Java 版本中恢复行为更改之前才有必要。
我遇到过类似的问题,但使用的是 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());
在这种情况下,输出是
java.awt.Dimension[width=53,height=25]
java.awt.Dimension[width=61,height=82]
注意:我的字体不同,这就是我得到不同尺寸的原因。
编辑:我在这样较长的示例中更改了您的 getTableCellRendererComponent,它对我有用。我使用的是 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;
}
根据之前的建议和对 JDK 资源的深入挖掘,我建议采用更简单的解决方案:
setSize(new Dimention(0, 0))
基于BasicTextUI.getPreferredSize 实施,它强制重新计算根视图大小
} else if (d.width == 0 && d.height == 0) {
// Probably haven't been layed out yet, force some sort of
// initial sizing.
rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
这个问题是关于 JEditorPane
在 Java 8 和 Java 9 中的不同行为。我想知道其他人是否有过同样的经历,是否可以Java 9 中的错误,如果可能,请在 Java 9 中输入您的意见来处理它。
上下文:在我们的(古老的)代码库中,我们使用 JTable
的子类,为了在其中一列中呈现多行 HTML,我们使用的是 HTML 的子类JEditorPane
。我们使用 JEditorPane.getPreferredSize()
来确定内容的高度,并使用它来设置 table 行的高度。多年来一直运作良好。在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());
Java8 中的输出(1.8.0_131):
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]
在Java 9 我第一次设置文字时,首选高度反映了它。以后每次都不会。
我已经搜索过是否可以找到有关可能导致此问题的错误的任何信息,但没有找到任何相关信息。
问题:这是预期的(改变)行为吗?是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 的输出:
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 的输出:
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();
现在 table 看起来和 Java 8 上的一样好。如果有必要,我想我们可以在生产代码中使用类似的修复程序,但这似乎是一种浪费。特别是如果只有在即将到来的 Java 版本中恢复行为更改之前才有必要。
我遇到过类似的问题,但使用的是 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());
在这种情况下,输出是
java.awt.Dimension[width=53,height=25]
java.awt.Dimension[width=61,height=82]
注意:我的字体不同,这就是我得到不同尺寸的原因。
编辑:我在这样较长的示例中更改了您的 getTableCellRendererComponent,它对我有用。我使用的是 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;
}
根据之前的建议和对 JDK 资源的深入挖掘,我建议采用更简单的解决方案:
setSize(new Dimention(0, 0))
基于BasicTextUI.getPreferredSize 实施,它强制重新计算根视图大小
} else if (d.width == 0 && d.height == 0) {
// Probably haven't been layed out yet, force some sort of
// initial sizing.
rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
}