Dam*_*ien 15 java swing word-wrap java-7
我有两个不同的编辑器使用JTextPane和Java 7中的奇怪错误,这些错误在以前的JVM版本中没有出现.它发生在包含样式文本或组件的长行中.
这是一个演示此错误的示例.在此示例中,每次插入字符时,都会对所有文本应用默认样式.我用JDK 1.7.0_04测试了它.
import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class BugWrapJava7 extends JFrame {
JTextPane jtp;
StyledDocument doc;
public BugWrapJava7() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
jtp = new JTextPane();
add(jtp, BorderLayout.CENTER);
jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
doc = jtp.getStyledDocument();
doc.addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
insert();
}
public void removeUpdate(DocumentEvent e) {
}
public void changedUpdate(DocumentEvent e) {
}
});
setSize(200, 200);
setVisible(true);
}
public void insert() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
}
});
}
public static void main(String[] args) {
new BugWrapJava7();
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:我的代码中有什么问题,或者它确实是Java 7中引入的新bug?如果它是一个新的JVM错误,是否有解决方法?
它可能与问题8666727有关,但问题在于错误的包装而不是滚动条的外观.
mKo*_*bel 16
对于期货读者,JDK 1.7.0_04中仍然存在bug.,
比较Java7和稳定的Java6,
<------ Java7 vs Java6 --->
<------ Java7 vs Java6 --->
<------ Java7 vs Java6 --->
<------ Java7 vs Java6 --->
来自代码
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class BugWrapJava7 {
private JFrame frame = new JFrame();
private JTextPane jtp;
private StyledDocument doc;
public BugWrapJava7() {
jtp = new JTextPane();
jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
doc = jtp.getStyledDocument();
doc.addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
insert();
}
public void removeUpdate(DocumentEvent e) {
insert();
}
public void changedUpdate(DocumentEvent e) {
insert();
}
public void insert() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
}
});
}
});
JScrollPane scroll = new JScrollPane(jtp);
scroll.setPreferredSize(new Dimension(200, 200));
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BugWrapJava7 bugWrapJava7 = new BugWrapJava7();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
调查了这个.原因是breakSpots缓存.看起来像LabelView
存储它们并且不会重新计算previos文本编辑的偏移量.如果我手动重置它们,则不会发生错误.
下面是一个解决方法(由于私有breakSpots字段而非常脏)
import java.awt.Dimension;
import java.lang.reflect.Field;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class BugWrapJava7 {
private JFrame frame = new JFrame();
private JTextPane jtp;
private StyledDocument doc;
public BugWrapJava7() {
jtp = new JTextPane();
jtp.setEditorKit(new MyStyledEditorKit());
jtp.setText("\ntype some text in the above empty line and check the wrapping behavior");
doc = jtp.getStyledDocument();
doc.addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
insert();
}
public void removeUpdate(DocumentEvent e) {
insert();
}
public void changedUpdate(DocumentEvent e) {
insert();
}
public void insert() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE);
doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false);
}
});
}
});
JScrollPane scroll = new JScrollPane(jtp);
scroll.setPreferredSize(new Dimension(200, 200));
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BugWrapJava7 bugWrapJava7 = new BugWrapJava7();
}
});
}
}
class MyStyledEditorKit extends StyledEditorKit {
private MyFactory factory;
public ViewFactory getViewFactory() {
if (factory == null) {
factory = new MyFactory();
}
return factory;
}
}
class MyFactory implements ViewFactory {
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new MyLabelView(elem);
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new ParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new BoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
// default to text display
return new LabelView(elem);
}
}
class MyLabelView extends LabelView {
public MyLabelView(Element elem) {
super(elem);
}
public View breakView(int axis, int p0, float pos, float len) {
if (axis == View.X_AXIS) {
resetBreakSpots();
}
return super.breakView(axis, p0, pos, len);
}
private void resetBreakSpots() {
try {
// HACK the breakSpots private fields
Field f=GlyphView.class.getDeclaredField("breakSpots");
f.setAccessible(true);
f.set(this, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
没有反射就少了黑客.基于模型更改时breakSpots的通常重置.
class MyLabelView extends LabelView {
boolean isResetBreakSpots=false;
public MyLabelView(Element elem) {
super(elem);
}
public View breakView(int axis, int p0, float pos, float len) {
if (axis == View.X_AXIS) {
resetBreakSpots();
}
return super.breakView(axis, p0, pos, len);
}
private void resetBreakSpots() {
isResetBreakSpots=true;
removeUpdate(null, null, null);
isResetBreakSpots=false;
// try {
// Field f=GlyphView.class.getDeclaredField("breakSpots");
// f.setAccessible(true);
// f.set(this, null);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
super.removeUpdate(e, a, f);
}
public void preferenceChanged(View child, boolean width, boolean height) {
if (!isResetBreakSpots) {
super.preferenceChanged(child, width, height);
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:这个也修复了TextSamplerDemo.我重置了所有标签视图的所有位置.
class MyStyledEditorKit extends StyledEditorKit {
private MyFactory factory;
public ViewFactory getViewFactory() {
if (factory == null) {
factory = new MyFactory();
}
return factory;
}
}
class MyFactory implements ViewFactory {
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new MyLabelView(elem);
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new MyParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new BoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
// default to text display
return new LabelView(elem);
}
}
class MyParagraphView extends ParagraphView {
public MyParagraphView(Element elem) {
super(elem);
}
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
super.removeUpdate(e, a, f);
resetBreakSpots();
}
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
super.insertUpdate(e, a, f);
resetBreakSpots();
}
private void resetBreakSpots() {
for (int i=0; i<layoutPool.getViewCount(); i++) {
View v=layoutPool.getView(i);
if (v instanceof MyLabelView) {
((MyLabelView)v).resetBreakSpots();
}
}
}
}
class MyLabelView extends LabelView {
boolean isResetBreakSpots=false;
public MyLabelView(Element elem) {
super(elem);
}
public View breakView(int axis, int p0, float pos, float len) {
if (axis == View.X_AXIS) {
resetBreakSpots();
}
return super.breakView(axis, p0, pos, len);
}
public void resetBreakSpots() {
isResetBreakSpots=true;
removeUpdate(null, null, null);
isResetBreakSpots=false;
}
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
super.removeUpdate(e, a, f);
}
public void preferenceChanged(View child, boolean width, boolean height) {
if (!isResetBreakSpots) {
super.preferenceChanged(child, width, height);
}
}
}
Run Code Online (Sandbox Code Playgroud)