Slow JEditorPane/JTextPane and performance improvements. Looking in the net from time to time on forums I see posts like “Slow opening pages in JTextPane” or “How to improve performance of big texts showing in JEditorPane”. For me the slow JEditorPane is rather common problem so I investigated this a bit and would like to write some notes to improve the speed. Hope they are useful. To understand what happens inside I created a custom EditorKit (HTMLEditorit extension) and replaced root view (HTMLBlockView extends BlockView). In the view I overrode layout() method to measure time spent on layout.
protected void layout(int width, int height) {
long start=System.currentTimeMillis();
super.layout(width, height);
long end=System.currentTimeMillis();
System.out.println("w="+width+" h="+height+" time="+(end-start));
}
Then I opened multiple pages and used different calls and methods measuring time spent here and there. The results are:
In conclusion: If neither of the advices above helps try to play with custom views, found which views took most of time and replace them with custom ones. NOTE: If you have your own experience how to make it faster please share/discuss your ideas and I’ll try describe them here.
import javax.swing.text.Element;
import javax.swing.text.View;
import javax.swing.text.html.BlockView;
public class HTMLBlockView extends BlockView {
public HTMLBlockView(Element elem) {
super(elem, View.Y_AXIS);
}
protected void layout(int width, int height) {
long start=System.currentTimeMillis();
if (width<Integer.MAX_VALUE) {
super.layout(width, height);
}
long end=System.currentTimeMillis();
System.out.println("w="+width+" h="+height+" time="+(end-start));
}
}
import javax.swing.text.Element;
import javax.swing.text.View;
import javax.swing.text.FlowView;
public class HTMLParagraphView extends javax.swing.text.html.ParagraphView {
public static int MAX_VIEW_SIZE=100;
public HTMLParagraphView(Element elem) {
super(elem);
strategy = new HTMLParagraphView.HTMLFlowStrategy();
}
public static class HTMLFlowStrategy extends FlowStrategy {
protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) {
View res=super.createView(fv, startOffset, spanLeft, rowIndex);
if (res.getEndOffset()-res.getStartOffset()> MAX_VIEW_SIZE) {
res = res.createFragment(startOffset, startOffset+ MAX_VIEW_SIZE);
}
return res;
}
}
public int getResizeWeight(int axis) {
return 0;
}
}
import javax.swing.text.html.*;
import javax.swing.text.html.ParagraphView;
import javax.swing.text.*;
public class MyEditorKit extends HTMLEditorKit {
ViewFactory factory=new MyViewFactory();
public ViewFactory getViewFactory() {
return factory;
}
class MyViewFactory extends HTMLFactory {
public View create(Element elem) {
AttributeSet attrs = elem.getAttributes();
Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute);
Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute);
if (o instanceof HTML.Tag) {
HTML.Tag kind = (HTML.Tag) o;
if (kind == HTML.Tag.HTML) {
return new HTMLBlockView(elem);
}
else if (kind == HTML.Tag.IMPLIED) {
String ws = (String) elem.getAttributes().getAttribute(CSS.Attribute.WHITE_SPACE);
if ((ws != null) && ws.equals("pre")) {
return super.create(elem);
}
return new HTMLParagraphView(elem);
} else if ((kind == HTML.Tag.P) ||
(kind == HTML.Tag.H1) ||
(kind == HTML.Tag.H2) ||
(kind == HTML.Tag.H3) ||
(kind == HTML.Tag.H4) ||
(kind == HTML.Tag.H5) ||
(kind == HTML.Tag.H6) ||
(kind == HTML.Tag.DT)) {
// paragraph
// return new ParagraphView(elem);
return new HTMLParagraphView(elem);
}
}
return super.create(elem);
}
}
}
The test application class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class App {
static String testText=null;
public App() {
}
public static void main(String[] args) {
App frame=new App();
frame.init().setVisible(true);
}
public JFrame init() {
JFrame frame = new JFrame("Performance test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JEditorPane editorCustom = new JEditorPane();
editorCustom.setEditorKit(new MyEditorKit());
final JScrollPane scroll = new JScrollPane(editorCustom);
editorCustom.getDocument().putProperty("i18n", Boolean.TRUE);
setText(editorCustom, "");
frame.getContentPane().add(scroll);
JToolBar tb=new JToolBar();
JButton btnSetText=new JButton("Set text");
tb.add(btnSetText);
btnSetText.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final int old=scroll.getVerticalScrollBarPolicy();
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setText(editorCustom, "");
scroll.setVerticalScrollBarPolicy(old);
}
});
}
});
JButton btnClear=new JButton("Clear");
tb.add(btnClear);
btnClear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editorCustom.setText("");
}
});
frame.getContentPane().add(tb, BorderLayout.NORTH);
frame.setBounds(0,0,400,400);
frame.setLocationRelativeTo(null);
return frame;
}
private void setText(JEditorPane editor, String txt) {
long t1=System.currentTimeMillis();
editor.setText(getTestText());
long t2=System.currentTimeMillis();
System.out.println(txt+" setText time="+(t2-t1));
}
public static String getTestText() {
if (testText ==null) {
String before="<html>\n" +
"<body>\n" +
"<p>\n" +
"Some text<br>\n"+
// "<img src=\"test.jpg\">\n" +
"</p>\n";
String mid= "<p>\n" +
"It's a long long long long long long long long long long" +
" long long long long long long long long long long long long" +
" long long long long long long long long long long long long" +
" long long long long long long long long long long long long" +
" long long long long long long long long long long long long" +
" long long long long long long long long long long long long"
" long long long long long text" +
"</p>\n";
StringBuffer buff=new StringBuffer(before);
for (int i=0; i<1000; i++) {
// for (int i=0; i<10000; i++) {
buff.append(mid);
}
String end= "</body>\n" +
"</html>";
buff.append(end);
System.out.println("HTML text length="+buff.length());
testText = buff.toString();
}
return testText;
}
}
Back to Table of Content |
||||||||