【问题标题】:Get a component from a JTextPane through javax.swing.text.Element?通过 javax.swing.text.Element 从 JTextPane 获取组件?
【发布时间】:2013-03-27 14:33:52
【问题描述】:

我使用JTextPane 来显示字符和符号,后者由自定义绘制的JComponents 表示。例如,文本窗格可能会显示如下内容: 文本窗格是用户可编辑的,并且允许用户通过在任何位置的按钮添加更多符号并作为所选文本的替换。我通过JTextPane.insertComponent() 方法做到这一点。在应用程序的某个时刻,我需要知道文本窗格中当前显示的内容,我指的不仅是输入的文本,还包括其中包含的确切组件。

我在使用PositionsDocumentListeners 来管理我的文本窗格的内容时遇到了很多麻烦,但我一直在造成比我解决的问题更多的问题。这就是为什么我最终决定,我的麻烦可能是由于我的设计错误,所以我决定看看,如果我不能通过文本窗格访问我的组件。

查了AbstractDocument等相关类的文档和源码,找到了接口javax.swing.text.Element。然后我让我的应用程序输出

for(int i = 0; i < textPane.getDocument().getLength(); i++) {
    System.out.println(((StyledDocument) textPane.getDocument()).getCharacterElement(i));
}

这给了我:

LeafElement(内容) 0,4

LeafElement(内容) 0,4

LeafElement(内容) 0,4

LeafElement(内容) 0,4

LeafElement(组件) 4,5

LeafElement(内容) 5,9

LeafElement(内容) 5,9

LeafElement(内容) 5,9

LeafElement(内容) 5,9

LeafElement(组件) 9,10

看到我得到的LeafElements 似乎确实有一些关于Document 中哪个位置显示的内容的信息,我想一定可以在那个位置获得实际内容。又找了半个小时如何获取每个元素所代表的内容,我放弃了,决定在这里发布我的问题,希望你们中的一些人可能知道如何完成这个!?

我见过这个question,有人试图通过textPane.getComponents() 访问组件,它返回一个组件数组,其中包含JTextPane 中实际包含的组件的确切数量,但它们都是@ 类型987654337@,显然对我没用。也许我只是不知道如何从这里正确继续,因为转换为我的符号的原始类型不起作用。

tl;dr

如何获得JComponent,它位于JTextPane 的文本内,以及它在文本窗格中的位置?

【问题讨论】:

  • 希望这个answer 可以帮助提供一些关于定位的想法。 +1 以获得更多关注 :-)
  • @Gagandeep Bali 感谢您的关注 :-)。您的回答很有趣,但不幸的是它不适用于我的问题,因为我不需要知道组件的Location,而是知道文本中的位置 as-in: index 。但是,如果我无法访问组件本身,那么所有这些都是无用的,这对我的目标来说是绝对必要的。
  • 啊哈,这方面的知识还不是我能掌握的。祝愿有智慧的人能够尽快阐明这个话题:-) 祝你好运......
  • This 帖子可能会有所帮助。
  • @ExtremeCoders 这确实有帮助。这样我就可以正确访问我的所有组件。由于两个原因,我还不能完全接受这个作为答案:1.您没有将其作为答案发布;2.我无法以这种方式获得每个组件的位置,或者我可以吗? (按位置,我的意思不是Location,而是索引。)

标签: java swing element jtextpane jcomponent


【解决方案1】:

您可以遍历文本窗格的StyledDocument 来查找代表组件或图标的元素,如下所示。

分支元素(部分)0,7 BranchElement(段落) 0,7 叶元素(内容)0,4 叶元素(图标)4,5 类 javax.swing.plaf.IconUIResource LeafElement(组件)5,6 类 javax.swing.JLabel 叶元素(内容)6,7

SSCCE:

/**
 * @see http://stackoverflow.com/a/15669307/230513
 * @see http://stackoverflow.com/questions/2883413
 */
public class DocumentParse {

    private static final String ELEM = AbstractDocument.ElementNameAttribute;
    private static final String ICON = StyleConstants.IconElementName;
    private static final String COMP = StyleConstants.ComponentElementName;

    public static void main(String args[]) throws Exception {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTextPane jtp = new JTextPane();
        StyledDocument doc = (StyledDocument) jtp.getDocument();
        SimpleAttributeSet normal = new SimpleAttributeSet();
        StyleConstants.setFontFamily(normal, "Serif");
        StyleConstants.setFontSize(normal, 72);
        StyleConstants.setForeground(normal, Color.blue);
        doc.insertString(doc.getLength(), "Test", normal);
        jtp.setSelectionStart(doc.getLength());
        jtp.insertIcon(UIManager.getIcon("OptionPane.warningIcon"));
        jtp.setSelectionStart(doc.getLength());
        jtp.insertComponent(new JLabel("Label"));
        jtp.setSelectionStart(doc.getLength());

        ElementIterator iterator = new ElementIterator(doc);
        Element element;
        while ((element = iterator.next()) != null) {
            System.out.println(element);
            AttributeSet as = element.getAttributes();
            if (as.containsAttribute(ELEM, ICON)) {
                System.out.println(StyleConstants.getIcon(as).getClass());
            }
            if (as.containsAttribute(ELEM, COMP)) {
                System.out.println(StyleConstants.getComponent(as).getClass());
            }
        }

        f.add(jtp);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

【讨论】:

  • 现在,这就是我一直在寻找的答案!我知道必须可以通过Elements 访问JTextPane 中的所有内容,但我只是不知道怎么做。后续问题: 1. 我怎么知道我必须向AttributeSet 询问StyleConstants.ComponentElementName,我的意思是我怎么知道在哪里寻找这种字符串常量? 2. 为什么ElementIterator在文档内容后给我一个换行符? (我得到LeafElement(content) 12,13,即使textPane.getDocument.getLength() 产生12!)
  • @SheridanVespo: 1. 老实说,我列举了getAttributeNames() 并在 API 中搜索命名常量。 2. 感谢AbstractDocument#toString()
  • 1.谢谢,也许这将帮助我解决我将来遇到的问题。 2.AbstractDocument没有toString()方法!?至少不是根据grepcode
  • @SheridanVespo:啊,AbstractDocument.BranchElement#toString();我在element.toString()放了一个断点来查看。
  • 但是那个函数确实是return "BranchElement(" + getName() + ") " + getStartOffset() + "," + getEndOffset() + "\n"; 所以,恕我直言最后没有解释额外的LeafElement!?
【解决方案2】:

原始组件是javax.swing.text.ComponentView$Invalidator 的第一个(也是唯一的)子组件,您可以从 ComponentView 中看到。

您可以获取无效器列表并使用它们的子级访问插入的组件。

【讨论】:

  • 查看 ComponentView 的源代码。实际上在布局视图动作 setComponentParent 被调用。它有代码 void setComponentParent() { View p = getParent(); if (p != null) { 容器父级 = getContainer(); if (parent != null) { if (c == null) { // 尝试构建一个组件 Component comp = createComponent(); if (comp != null) { createdC = comp; c = new Invalidator(comp); } }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
  • 2014-01-30
相关资源
最近更新 更多