java 如何在 JTextPane 中将每个字符设置为不同的颜色/背景色?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13074428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:24:17  来源:igfitidea点击:

How can I set each character to a different color/background color in a JTextPane?

javaswingjtextpanejtextcomponentstyleddocument

提问by JaredL

I've been searching for this for a while and so far all I've been able to come up with is how to create a style and apply it to a character like so:

我一直在寻找这个,到目前为止,我能想出的只是如何创建一种样式并将其应用到这样的角色上:

StyledDocument doc = (StyledDocument) new DefaultStyledDocument();
JTextPane textpane = new JTextPane(doc);
textpane.setText("Test");
javax.swing.text.Style style = textpane.addStyle("Red", null);
StyleConstants.setForeground(style, Color.RED);
doc.setCharacterAttributes(0, 1, textpane.getStyle("Red"), true); 

This is useful if you have only a few styles in your document and want to store them by name so that you can apply them easily later on. In my application I want to be able to set the foreground color (one of only a few values) and the background color (grayscale, many different values) independently for every character in the text. It seems like a huge waste to create potentially hundreds/thousands of different styles for this. Is there a way to set these attributes without having to create a new style each time? It would be much easier if I only had to render the text but I also need to make it editable as well. Is there a way to do this with JTextPane, or is there another swing class that offers this functionality?

如果您的文档中只有几个样式并且想要按名称存储它们以便您以后可以轻松地应用它们,这将非常有用。在我的应用程序中,我希望能够为文本中的每个字符独立设置前景色(仅有的几个值之一)和背景色(灰度,许多不同的值)。为此创造潜在的成百上千种不同的风格似乎是一种巨大的浪费。有没有办法设置这些属性而不必每次都创建新样式?如果我只需要渲染文本会容易得多,但我还需要使其可编辑。有没有办法做到这一点JTextPane,或者是否有另一个提供此功能的摆动类?

回答by Guillaume Polet

If you want to change the style for each character in a textpane, here is a complete random way to do it. You create a different attribute set for each character. Up to you to find appropriate combination (foreground/background contrast, not too much difference in size of the chars, etc...). You could also store the different styles you have already applied so that you don't use the same one twice.

如果您想更改文本窗格中每个字符的样式,这是一种完全随机的方法。您为每个角色创建不同的属性集。由您来找到合适的组合(前景/背景对比度,字符大小差异不大,等等......)。您还可以存储已应用的不同样式,以免重复使用相同的样式。

enter image description here

在此处输入图片说明

import java.awt.Color;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class TestDifferentStyles {
    private void initUI() {
        JFrame frame = new JFrame(TestDifferentStyles.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        StyledDocument doc = new DefaultStyledDocument();
        JTextPane textPane = new JTextPane(doc);
        textPane.setText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has "
                + "been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of "
                + "type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the "
                + "leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the"
                + " release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing "
                + "software like Aldus PageMaker including versions of Lorem Ipsum.");

        Random random = new Random();
        for (int i = 0; i < textPane.getDocument().getLength(); i++) {
            SimpleAttributeSet set = new SimpleAttributeSet();
            // StyleConstants.setBackground(set, new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
            StyleConstants.setForeground(set, new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
            StyleConstants.setFontSize(set, random.nextInt(12) + 12);
            StyleConstants.setBold(set, random.nextBoolean());
            StyleConstants.setItalic(set, random.nextBoolean());
            StyleConstants.setUnderline(set, random.nextBoolean());

            doc.setCharacterAttributes(i, 1, set, true);
        }

        frame.add(new JScrollPane(textPane));
        frame.setSize(500, 400);
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestDifferentStyles().initUI();
            }
        });
    }

}

回答by David Kroukamp

I'm not sure what you mean, but cant you loop through each character in the JtextPaneand within that loop iterate through all letters/characters you want to highlight etc. Have an ifstatement checking the character and then set the Styleaccordingly.

我不确定你的意思,但你不能循环遍历每个字符,JtextPane并在该循环中遍历你想要突出显示的所有字母/字符等。有一个if语句检查字符,然后相应地设置Style

Here is an example I made I only implemented it for the characters hand wfor demonstration purposes:

这是我制作的一个示例,我仅为演示目的为字符hw实现了它:

enter image description here

在此处输入图片说明

//necessary imports
import java.awt.Color;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class Test {

    /**
     * Default constructor for Test.class
     */
    public Test() {
        initComponents();
    }

    public static void main(String[] args) {

        /**
         * Create GUI and components on Event-Dispatch-Thread
         */
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Test test = new Test();
            }
        });
    }

    /**
     * Initialize GUI and components (including ActionListeners etc)
     */
    private void initComponents() {
        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        StyledDocument doc = (StyledDocument) new DefaultStyledDocument();
        JTextPane textPane = new JTextPane(doc);
        textPane.setText("Hello, world! :)");

        //create necessary styles for various characters
        javax.swing.text.Style style = textPane.addStyle("Red", null);
        StyleConstants.setForeground(style, Color.RED);
        javax.swing.text.Style style2 = textPane.addStyle("Blue", null);
        StyleConstants.setForeground(style2, Color.BLUE);

        //create array of characters to check for and style
        String[] lettersToEdit = new String[]{"h", "w"};

        //create arraylist to hold each character in textPane
        ArrayList<String> strings = new ArrayList<>();

        //get all text
        String text = textPane.getText();

        //populate arraylist
        for (int i = 0; i < text.length(); i++) {
            strings.add(text.charAt(i) + "");
        }

        //declare variabe to hold position
        int position = 0;

        for (String s1 : strings) {//for each character in the textpane text
            for (String s2 : lettersToEdit) {//for each character in array to check (lettersToEdit)
                if (s2.toLowerCase().equalsIgnoreCase(s1)) {//if there was a match

                    System.out.println("found a match: " + s1);
                    System.out.println("counter: " + position + "/" + (position + 1));

                    //check which chacacter we matched
                    if (s1.equalsIgnoreCase(lettersToEdit[0])) {
                        //set appropriate style
                        doc.setCharacterAttributes(position, 1, textPane.getStyle("Red"), true);
                    }
                    if (s1.equalsIgnoreCase(lettersToEdit[1])) {
                        doc.setCharacterAttributes(position, 1, textPane.getStyle("Blue"), true);
                    }
                }
            }
            //increase position after each character on textPane is parsed
            position++;
        }

        jFrame.add(textPane);
        //pack frame (size JFrame to match preferred sizes of added components and set visible
        jFrame.pack();
        jFrame.setVisible(true);
    }
}

回答by jfajunior

I think the best way you have to do this is like we have in editors with highlight, not chasing for characters, but having a pattern, for instance:

我认为你必须做到这一点的最佳方式就像我们在编辑器中使用高亮显示,不是追逐字符,而是有一个模式,例如:

private static HashMap<Pattern, Color> patternColors;
private static String GENERIC_XML_NAME = "[A-Za-z]+[A-Za-z0-9\-_]*(:[A-Za-z]+[A-Za-z0-9\-_]+)?";
private static String TAG_PATTERN = "(</?" + GENERIC_XML_NAME + ")";
private static String TAG_END_PATTERN = "(>|/>)";
private static String TAG_ATTRIBUTE_PATTERN = "(" + GENERIC_XML_NAME + ")\w*\=";
private static String TAG_ATTRIBUTE_VALUE = "\w*\=\w*(\"[^\"]*\")";
private static String TAG_COMMENT = "(<\!--[\w ]*-->)";
private static String TAG_CDATA = "(<\!\[CDATA\[.*\]\]>)";

private static final Color COLOR_OCEAN_GREEN = new Color(63, 127, 127);
private static final Color COLOR_WEB_BLUE = new Color(0, 166, 255);
private static final Color COLOR_PINK = new Color(127, 0, 127);

static {
    // NOTE: the order is important!
    patternColors = new LinkedHashMap<Pattern, Color>();
    patternColors.put(Pattern.compile(TAG_PATTERN), Color.BLUE); // COLOR_OCEAN_GREEN | Color.BLUE
    patternColors.put(Pattern.compile(TAG_CDATA), COLOR_WEB_BLUE);
    patternColors.put(Pattern.compile(TAG_ATTRIBUTE_PATTERN), COLOR_PINK);
    patternColors.put(Pattern.compile(TAG_END_PATTERN), COLOR_OCEAN_GREEN);
    patternColors.put(Pattern.compile(TAG_COMMENT), Color.GRAY);
    patternColors.put(Pattern.compile(TAG_ATTRIBUTE_VALUE), COLOR_OCEAN_GREEN); //Color.BLUE | COLOR_OCEAN_GREEN
}




public XmlView(Element element) {

    super(element);

    // Set tabsize to 4 (instead of the default 8).
    getDocument().putProperty(PlainDocument.tabSizeAttribute, 4);
}