2012-08-15 57 views
4

我無法弄清楚JEditorPane.scrollToReference()是如何用於動態生成的HTML頁面的。我想打開一個JEditorPane對話框,滾動到我選擇的錨點。無論我如何解決問題,視圖總是在頁面底部滾動。帶動態生成HTML的JEditorPane.scrollToReference()

作爲一個醜陋的解決辦法,我現在解析爲錨標籤的完整的HTML文檔,保存他們的偏移量在Map<String, Integer>,然後我打電話:

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

...這甚至不產生吸引力結果,因爲可見矩形內的插入符號位置看起來不可預知,並且很少位於窗口頂部。我正在尋找更類似於瀏覽器的行爲,其中錨定文本出現在可見區域的頂部。

下面是什麼我尷尬的解決方法發生截圖(上有「頭6」錨),而不必觸及滾動條:

screenshot http://i49.tinypic.com/jkaj9s.png

我想我失去了一些東西但我無法弄清楚究竟是什麼。

我目前的解決方法來源:

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"); // doesn't 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(); 
    } 
} 

回答

5

這個問題可能是因爲面板尚不可見或不執行時scrollToReference又擺出來,所以無法確定其大小。

scrollToReference的實施方案具有下列塊:

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

在張貼示例的矩形是爲nullanchor6,由於視圖尚未可見或它的大小不爲正。

試試這個骯髒的修復延遲滾動:

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

我有同樣的想法,你,但它並沒有區別,當我嘗試過。你有不同的結果嗎? – 2012-08-15 21:41:14

+0

@NickRippe是的,它滾動確定。 – tenorsax 2012-08-15 21:43:01

+0

啊,是的 - 現在我可以開始工作。 'showMessageDialog'和'scrollToReference'都需要位於'invokeLater'語句中(按此順序)。我一定有一些東西被弄糊塗了。 +1 – 2012-08-15 21:57:08