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

喜欢而已 提交于 2019-11-26 16:54:34

问题


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?


回答1:


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.

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();
            }
        });
    }

}



回答2:


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

Here is an example I made I only implemented it for the characters h and w for demonstration purposes:

//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);
    }
}



回答3:


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);
}


来源:https://stackoverflow.com/questions/13074428/how-can-i-set-each-character-to-a-different-color-background-color-in-a-jtextpan

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!