JEditorPane.scrollToReference () with dynamically generated HTML

I can't figure out how JEditorPane.scrollToReference() designed to be used with a dynamically generated HTML page. I would like to open a dialog with JEditorPane, which scrolls to the anchor of my choice. No matter how I approach the problem, the view always scrolls at the bottom of the page.

As an ugly workaround, I am currently analyzing the entire HTML document for tag binding, storing their offsets in Map<String, Integer> , and then calling:

 editorPane.setCaretPosition(anchorMap.get("anchor-name")); 

... which does not even give an attractive result, since the position of the carriage in the visible rectangular box looks unpredictable and is rarely located at the top of the window. I'm looking for a more browser-like behavior when pinned text appears at the top of the visible area.

Below is a screenshot of what happens to my inconvenient workaround (there is a binding on the β€œheader 6”) without touching the scrollbar:

screenshot

I think I missed something, but I can’t understand what exactly.

Source of my current solution:

 import javax.swing.*; import javax.swing.text.MutableAttributeSet; import javax.swing.text.html.*; import javax.swing.text.html.HTMLEditorKit.*; import javax.swing.text.html.parser.*; import java.io.*; import java.awt.*; import java.util.HashMap; public class AnchorTest { public static void main(String[] args) { final String html = generateLongPage(); final HashMap<String, Integer> anchors = anchorPositions(html); SwingUtilities.invokeLater(new Runnable() { public void run() { JEditorPane editor = new JEditorPane("text/html", html); JScrollPane scroller= new JScrollPane(editor); scroller.setPreferredSize(new Dimension(400, 250)); //editor.scrollToReference("anchor6"); // does not work... editor.setCaretPosition(anchors.get("anchor6")); //sorta works JOptionPane.showMessageDialog(new JPanel(), scroller, "", JOptionPane.PLAIN_MESSAGE); }}); } public static HashMap<String, Integer> anchorPositions(String html) { final HashMap<String, Integer> map = new HashMap<String, Integer>(); Reader reader = new StringReader(html); HTMLEditorKit.Parser parser = new ParserDelegator(); try { ParserCallback cb = new ParserCallback() { public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { if (t == HTML.Tag.A) { String name = (String)a.getAttribute(HTML.Attribute.NAME); map.put(name, pos); } } }; parser.parse(reader, cb, true); } catch (IOException ignore) {} return map; } public static String generateLongPage() { StringBuilder sb = new StringBuilder( "<html><head><title>hello</title></head><body>\n"); for (int i = 0; i < 10; i++) { sb.append(String.format( "<h1><a name='anchor%d'>header %d</a></h1>\n<p>", i, i)); for (int j = 0; j < 100; j++) { sb.append("blah "); } sb.append("</p>\n\n"); } return sb.append("</body></html>").toString(); } } 
+4
source share
1 answer

The problem is probably due to the fact that the panel is not displayed or until it is displayed when scrollToReference is scrollToReference , so its size cannot be determined.

The scrollToReference implementation has the following block:

 Rectangle r = modelToView(iter.getStartOffset()); if (r != null) { ... scrollRectToVisible(r); } 

In the presented example, the null rectangle for anchor6 , since the view is not yet visible or its size is not positive.

Try this dirty fix to postpone scrolling:

 SwingUtilities.invokeLater(new Runnable() { public void run() { editor.scrollToReference("anchor6"); } }); JOptionPane.showMessageDialog(new JPanel(), scroller, "", JOptionPane.PLAIN_MESSAGE); 
+4
source

All Articles