在JEditorPane中着色文本的某些部分会使前景色彩化失败

时间:2014-05-19 13:09:19

标签: java swing jeditorpane

我希望使用JEditorPane以某种颜色(比如绿色)显示一些文本,当用户输入文本时,并在某些条件下更改某些部分的颜色(例如:第0到第9个字符为红色)满足了。

所以基本上,我需要一个默认的前景色,并且需要动态改变文本颜色的某些部分。到目前为止,我的尝试如下。但是,setForeground()方法似乎无法解决问题。我该如何解决这个问题?遗憾的是,使用类似JTextPane的东西不是一种选择,因为JTextPane中的一些问题使得它不适合我正在处理的事情。谢谢!

SSCCE:

 public class ColoredStrikeThroughText {
    public ColoredStrikeThroughText() {
        JFrame fr = new JFrame("Custom color attribute");

        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JEditorPane pane = new JEditorPane();

        pane.setForeground(Color.GREEN);
        pane.setEditorKit(new StyledEditorKit() {
            public ViewFactory getViewFactory() {
                return new NewViewFactory();

            }
        });

        pane.setText("Color red text, color blue text, text without coloring.");

        StyledDocument doc = (StyledDocument) pane.getDocument();
        MutableAttributeSet attr = new SimpleAttributeSet();

        StyleContext sc = StyleContext.getDefaultStyleContext();
        AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.red);

        attr.addAttributes(aset);

        doc.setCharacterAttributes(0, 9, attr, false);

        aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.blue);
        attr.addAttributes(aset);
        doc.setCharacterAttributes(17, 27, attr, false);
        JScrollPane sp = new JScrollPane(pane);

        fr.getContentPane().add(sp);
        fr.setSize(300, 300);
        fr.setLocationRelativeTo(null);

        fr.setVisible(true);
    }

    public static void main(String[] args) {
        ColoredStrikeThroughText test = new ColoredStrikeThroughText();
    }
}

class NewViewFactory implements ViewFactory {
    public View create(Element elem) {
        String kind = elem.getName();
        if (kind != null) {
            if (kind.equals(AbstractDocument.ContentElementName)) {
                return new LabelView(elem);
            } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                return new ParagraphView(elem);
            } else if (kind.equals(AbstractDocument.SectionElementName)) {
                return new BoxView(elem, View.Y_AXIS);
            } else if (kind.equals(StyleConstants.ComponentElementName)) {
                return new ComponentView(elem);
            } else if (kind.equals(StyleConstants.IconElementName)) {
                return new IconView(elem);
            }
        }
        // default to text display
        return new LabelView(elem);
    }
}

class MyLabelView extends LabelView {

    public MyLabelView(Element elem) {
        super(elem);
    }


}

编辑1:

谢谢大家。我担心我的问题没有澄清一些事情。因为我担心这个问题可能会变得太长,所以我把这些东西都遗漏了,但是我会在这里发布,因为似乎没有其他方法可以澄清:

1)为什么我没有使用JTextPane。原因是当我使用它时,自动换行不能正常工作:

SSCCE:

public class nowrapsscce extends JPanel{
    public  nowrapsscce() {

        JFrame j = new JFrame();

            JEditorPane inputPane = new JEditorPane(); //replace JEditorPane with 
//JTextPane here to see how word wrapping fails

        inputPane.setBackground(Color.BLACK);
        inputPane.setForeground(Color.LIGHT_GRAY);
        inputPane.setCaretColor(Color.LIGHT_GRAY);

        JEditorPane noninputPane = new JEditorPane();

        noninputPane.setEditable(false);
        noninputPane.setText("Test ");
        noninputPane.setPreferredSize(new Dimension(40, 200));

        noninputPane.setBackground(Color.WHITE);
        noninputPane.setForeground(Color.BLACK);

        JPanel promptInputPanel = new JPanel(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.LINE_START;
        c.fill = GridBagConstraints.VERTICAL;
        c.weighty = 1.0;
        c.weightx = 0;
        promptInputPanel.add(noninputPane, c);

        c.anchor = GridBagConstraints.LINE_END;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.weightx = 1.0;
        c.fill = GridBagConstraints.BOTH;
        promptInputPanel.add(inputPane, c);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBorder(new EtchedBorder());

        scrollPane.setViewportView(promptInputPanel);
        scrollPane
                .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        j.add(scrollPane);
        j.setVisible(true);
        j.pack();

    }

    public static void main(String[] args) {
        nowrapsscce test = new nowrapsscce();
    }
}

2)我不能将所有文本变为白色,然后在它的某些部分着色,因为我希望用户输入文本,并且默认情况下整个文本显示为白色,就像在SSCCE中一样。拥有一个keylistener并且逐个字符的整个白色字符可能效率太低。如果某些单词与给定的单词匹配,我想基本上对其进行着色,但是在侧面使用这个新的,不可编辑的JTextPane / JEditorPane,就像在SSCCE中一样,这是问题的转折。

再次感谢:)

2 个答案:

答案 0 :(得分:3)

解决方法:在执行任何自定义着色之前设置整个文本的前景色将解决您的问题JEditorPane

AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, 
                                     StyleConstants.Foreground,Color.GREEN);
attr.addAttributes(aset);
// set foreground for all the text
doc.setCharacterAttributes(0, pane.getText().length(), attr, false);

如果您可以选择JTextPane而不是JEditorPane,那么它将解决问题。

截图:

enter image description here


修改

  

为什么我没有使用JTextPane。原因是当我使用它时,自动换行无效?

这是自定义JTextPane类。您可以尝试使用此类来解决包装问题。

示例代码:

public class NonWrappingTextPane extends JTextPane {
    public NonWrappingTextPane() {
        super();
    }

    public NonWrappingTextPane(StyledDocument doc) {
        super(doc);
    }

    // Override getScrollableTracksViewportWidth
    // to preserve the full width of the text
    public boolean getScrollableTracksViewportWidth() {
        Container parent = getParent();
        ComponentUI ui = getUI();

        return parent != null ? (ui.getPreferredSize(this).width <= parent.getSize().width) : true;
    }
}

在此处查找完整代码Non Wrapping(Wrap) TextPane

截图:

enter image description here

答案 1 :(得分:1)

这将使用指定的相应颜色对指定单词的出现进行着色:

public class Colorer extends JFrame {

    Pattern pat;
    Map<String, SimpleAttributeSet> map = new HashMap<>();
    JEditorPane editor = new JEditorPane();

    public Colorer() {

        String[] words = {"atext1", "atext", "text1"};
        Color[] colors = {Color.RED, Color.GREEN, Color.BLUE};
        StringBuilder sb = new StringBuilder(); // You can use words.length*8 in the constructor argument to estimate the capacity.
        for (int i = 0; i < words.length; i++) {
            sb.append("("+words[i]+")" + "|");
            SimpleAttributeSet sas = new SimpleAttributeSet();
            StyleConstants.setForeground(sas, colors[i]);
            map.put(words[i], sas);
        }
        sb.deleteCharAt(sb.length()-1);
        pat = Pattern.compile(sb.toString());

        editor.setEditorKit(new StyledEditorKit());
        editor.setDocument(new DefaultStyledDocument());
        editor.getDocument().addDocumentListener(new ColorDocumentLister());

        getContentPane().add(new JScrollPane(editor));
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    private class ColorDocumentLister implements DocumentListener {

        SimpleAttributeSet black = new SimpleAttributeSet();

        ColorDocumentLister() {

            StyleConstants.setForeground(black, Color.BLACK);
        }

        public void insertUpdate(DocumentEvent e) {

            SwingUtilities.invokeLater(new Runnable() {

                public void run() {

                    finaAndColor();
                }
            });
        }

        public void removeUpdate(DocumentEvent e) {

            SwingUtilities.invokeLater(new Runnable() {

                public void run() {

                    finaAndColor();
                }
            });
        }

        public void changedUpdate(DocumentEvent e) {

        }

        private void finaAndColor() {

            StyledDocument doc = (StyledDocument) editor.getDocument();
            doc.setCharacterAttributes(0, doc.getLength(), black, true);

            Matcher m = pat.matcher(editor.getText());
            while (m.find()) {
                doc.setCharacterAttributes(m.start(), m.end(), map.get(m.group()), true);
                doc.setCharacterAttributes(m.end(), doc.getLength(), black, true);
            }   
        }
    }

    public static void main(String[] args) {

        new Colorer();
    }
}

备注:

  • 这可能不是实现此功能的正确方法,但这是我目前可以提供的功能。
  • 一个问题是,每次在文本编辑器中添加或删除文本时,都会创建一个包含整个内容的新字符串 - 对于大型内容来说效率非常低。
  • 根据更大的图片(您的最终目标),您需要修改此实现以获得更好的性能,功能和设计逻辑。