【问题标题】:Swing HTMLDocument doesn't contain all the HTML elements?Swing HTMLDocument 不包含所有的 HTML 元素?
【发布时间】:2016-06-03 12:53:44
【问题描述】:

我有一个 swing 应用程序,其中包含一个显示 HTML 文件的对话框。我是这样做的:

URL url = getClass().getResource("/resources/EULA.html");

JDialog eulaDialog = new JDialog();
JEditorPane eulaEP = new JEditorPane();
try {
  eulaEP.setPage(url);
} catch (IOException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
}

JScrollPane scrollPane = new JScrollPane(eulaEP);
eulaDialog.getContentPane().add(scrollPane);
eulaDialog.setBounds(400, 200, 700, 600);
eulaDialog.setVisible(true);

这按我的预期工作。它可以正确显示 HTML 文件。

我现在尝试在文档中找到一个元素,所以我这样做:

HTMLDocument htm = (HTMLDocument) eulaEP.getDocument();
Element el = htm.getElement("unique_id");

但这会返回 null(即使该元素显示在对话框中)。

我决定通过这样做来检查文档中包含哪些元素:

for (ElementIterator iterator = new ElementIterator(htm); iterator.next() != null;)

但这只返回了 4 个元素; html、正文、p 和内容。我的 HTML 文件还有很多(内容是什么?)我做错了什么?

澄清一下,HTML 包含一个按钮,我想在这个按钮上添加一个 ActionListener,这样我就可以在我的 java 代码中点击它。

【问题讨论】:

  • “HTML 包含一个按钮,我想在这个按钮上添加一个 ActionListener” 祝你好运!我会在 GUI 的其他地方放置一个按钮。为了尽快获得更好的帮助,请发布minimal reproducible exampleShort, Self Contained, Correct Example。在源代码中将 HTML 硬编码为 String
  • eulaDialog.setBounds(400, 200, 700, 600); Java GUI 必须在不同的操作系统、屏幕尺寸、屏幕分辨率等上使用不同语言环境中的不同 PLAF。因此,它们不利于像素完美布局。而是使用布局管理器,或 combinations of them 以及 white space 的布局填充和边框。
  • 我不明白你最后的评论。我正在创建一个对话框,setBounds 只是设置屏幕上窗口的宽度、高度和 x、y 位置,不是吗?这与布局管理器有什么关系?
  • “我不明白你的最后一条评论。” 当我写下这段话时,我以为JComponent 被定位在JPanel 中。话虽如此,可能有更好的方法来定位和调整它的大小。那个 MCVE 在哪里?

标签: java swing jeditorpane


【解决方案1】:

我的猜测是您在文档完全加载之前正在阅读它。 doocumentation for JEditorPane.setPage 对此提供了很多信息:

这可以根据 EditorKit 返回的文档同步或异步加载。 …如果文档是异步加载的,文档将立即安装到编辑器中,使用调用 setDocument 将触发文档属性更改事件,然后将创建一个线程,该线程将开始执行实际加载。在这种情况下,页面属性更改事件不会被直接调用此方法触发,而是会在执行加载的线程完成时触发。它也将在事件调度线程上触发。

因此,在加载之前,您不应该查看文档。例如:

JEditorPane eulaEP = new JEditorPane();
eulaEP.addPropertyChangeListener("page", e -> {
    HTMLDocument htm = (HTMLDocument) eulaEP.getDocument();
    Element el = htm.getElement("unique_id");
    // ...
});

try {
  eulaEP.setPage(url);
} catch (IOException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
}

【讨论】:

    【解决方案2】:

    在下面的示例中,HTMLDocument::getElement(String id) 查找Element,其HTML.Attribute.id 属性的值为"unique_id"ElementBranchElement(div) 1,6

    我不确定您的Element 迭代在哪里出错,但您可以在下面的控制台输出中看到BranchElement(div) 中的unique_id 值。因为HTMLDocument 模拟HTML,所以封闭的HTMLReader 可能会合成HTML.Tag CONTENT,如下面的隐含段落中的内容。

    控制台:

    BranchElement(div) 1,6
    
    Element: 'BranchElement(html) 0,6', name: 'html', children: 2, attributes: 1, leaf: false
      Attribute: 'name', Value: 'html'
    Element: 'BranchElement(head) 0,1', name: 'head', children: 1, attributes: 1, leaf: false
      Attribute: 'name', Value: 'head'
    Element: 'BranchElement(p-implied) 0,1', name: 'p-implied', children: 1, attributes: 1, leaf: false
      Attribute: 'name', Value: 'p-implied'
    Element: 'LeafElement(content) 0,1', name: 'content', children: 0, attributes: 2, leaf: true
      Attribute: 'CR', Value: 'true'
      Attribute: 'name', Value: 'content'
        Content (0-1): ''
    Element: 'BranchElement(body) 1,6', name: 'body', children: 1, attributes: 1, leaf: false
      Attribute: 'name', Value: 'body'
    Element: 'BranchElement(div) 1,6', name: 'div', children: 1, attributes: 3, leaf: false
      Attribute: 'align', Value: 'center'
      Attribute: 'id', Value: 'unique_id'
      Attribute: 'name', Value: 'div'
    Element: 'BranchElement(p-implied) 1,6', name: 'p-implied', children: 2, attributes: 1, leaf: false
      Attribute: 'name', Value: 'p-implied'
    Element: 'LeafElement(content) 1,5', name: 'content', children: 0, attributes: 1, leaf: true
      Attribute: 'name', Value: 'content'
        Content (1-5): 'Test'
    Element: 'LeafElement(content) 5,6', name: 'content', children: 0, attributes: 2, leaf: true
      Attribute: 'CR', Value: 'true'
      Attribute: 'name', Value: 'content'
        Content (5-6): ''
    

    代码:

    import java.awt.EventQueue;
    import java.util.Enumeration;
    import javax.swing.JEditorPane;
    import javax.swing.JFrame;
    import javax.swing.text.AttributeSet;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.Element;
    import javax.swing.text.ElementIterator;
    import javax.swing.text.StyleConstants;
    import javax.swing.text.html.HTML;
    import javax.swing.text.html.HTMLDocument;
    
    /**
     * @see http://stackoverflow.com/a/5614370/230513
     */
    public class Test {
    
        private static final String TEXT
            = "<html>"
            + "<head></head>"
            + "<body>"
            + "<div align=center id=unique_id>Test</div>"
            + "</body>"
            + "</html>";
    
        public static void main(String[] args) throws Exception {
            EventQueue.invokeLater(new Test()::display);
        }
    
        private void display() {
            JFrame f = new JFrame("Test");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JEditorPane jep = new JEditorPane("text/html", TEXT);
            jep.setEditable(false);
            f.add(jep);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
    
            HTMLDocument htmlDoc = (HTMLDocument) jep.getDocument();
            System.out.println(htmlDoc.getElement("unique_id"));
            ElementIterator iterator = new ElementIterator(htmlDoc);
            Element element;
            while ((element = iterator.next()) != null) {
                try {
                    printElement(htmlDoc, element);
                } catch (BadLocationException e) {
                    e.printStackTrace(System.err);
                }
            }
        }
    
        private void printElement(HTMLDocument htmlDoc, Element element) throws BadLocationException {
            AttributeSet attrSet = element.getAttributes();
            System.out.println(""
                + "Element: '" + element.toString().trim()
                + "', name: '" + element.getName()
                + "', children: " + element.getElementCount()
                + ", attributes: " + attrSet.getAttributeCount()
                + ", leaf: " + element.isLeaf());
            Enumeration attrNames = attrSet.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                Object attr = attrNames.nextElement();
                System.out.println("  Attribute: '" + attr + "', Value: '"
                    + attrSet.getAttribute(attr) + "'");
                Object tag = attrSet.getAttribute(StyleConstants.NameAttribute);
                if (attr == StyleConstants.NameAttribute
                    && tag == HTML.Tag.CONTENT) {
                    int startOffset = element.getStartOffset();
                    int endOffset = element.getEndOffset();
                    int length = endOffset - startOffset;
                    System.out.printf("    Content (%d-%d): '%s'\n", startOffset,
                        endOffset, htmlDoc.getText(startOffset, length).trim());
                }
            }
        }
    }
    

    【讨论】:

    • 我已根据对您问题的仔细阅读更新了我的答案。我以为你想要名为unique_id 的属性的值;看起来您希望 id 的值为 "unique_id"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2011-09-06
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    相关资源
    最近更新 更多