Changing color of selected text in jTextPane
Asked Answered
B

5

7

I am creating a text editor using a JTextPane that allows the user to change the color of selected text. But when the user selects the text, then chooses the option to change the color (say, to red) the text does not appear as red until the text is unselected. I tried using setSelectedTextColor to change the color of the selected text, but that doesn't work since that changes the text to red anytime text is selected afterwards. Is there a way to have selected text show up as it's actual color? Or like the way it works in Word where it's not the actual color of the text, but when text of different colors are selected they show up as different colors even when selected.

I use the following code to set up the JTextPane and button that changes the selected text to red:

JButton redButton = new JButton(new StyledEditorKit.ForegroundAction("red", Color.RED));
redButton.setFocusable(false);
buttonPanel.add(redButton);

The JTextPane is set up as with content type HTML and uses the HTMLEditorKit:

p=new JTextPane();
p.setSize(300, 300);
kit = new HTMLEditorKit();
p.setEditorKit(kit);
p.setDocument(kit.createDefaultDocument());

p.setContentType("text/html");
p.setEditable(true);

Let me know if you need more source code to understand the question. Thank You!

Bassist answered 30/9, 2013 at 16:13 Comment(0)
H
5

Take a look at the DefaultHighlightPainter inner class of DefaultHighlighter.

The method

    public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
        Rectangle alloc = bounds.getBounds();
        try {
            // --- determine locations ---
            TextUI mapper = c.getUI();
            Rectangle p0 = mapper.modelToView(c, offs0);
            Rectangle p1 = mapper.modelToView(c, offs1);

            // --- render ---
            Color color = getColor();

            if (color == null) {
                g.setColor(c.getSelectionColor());
            }
            else {
                g.setColor(color);
            }

As you can see it uses either getColor() or getSelectionColor(). You can extend the class and adapt the highlight painting.

Or use a simpler approach to override your JTextPane's getSelectionColor(). In the method just check whether text is selected and use attributes of selected elements to get desired ccolor. If nothing is selected just return super.getSelectedColor()

UPDATE: Actually applying colors for selection is used on low level GlyphView's public void paint(Graphics g, Shape a) { ... JTextComponent tc = (JTextComponent) c; Color selFG = tc.getSelectedTextColor();

        if (// there's a highlighter (bug 4532590), and
            (tc.getHighlighter() != null) &&
            // selected text color is different from regular foreground
            (selFG != null) && !selFG.equals(fg)) {

            Highlighter.Highlight[] h = tc.getHighlighter().getHighlights();
            if(h.length != 0) {
                boolean initialized = false;
                int viewSelectionCount = 0;
                for (int i = 0; i < h.length; i++) {
                    Highlighter.Highlight highlight = h[i];
                    int hStart = highlight.getStartOffset();
                    int hEnd = highlight.getEndOffset();
                    if (hStart > p1 || hEnd < p0) {
                        // the selection is out of this view
                        continue;
                    }
                    if (!SwingUtilities2.useSelectedTextColor(highlight, tc)) {
                        continue;
                    }

...

As you can see applying selection color vs default color of the view is defined in the SwingUtilities2.useSelectedTextColor(highlight, tc)

In the sources http://kickjava.com/src/com/sun/java/swing/SwingUtilities2.java.htm

 public static boolean useSelectedTextColor(Highlighter.Highlight  JavaDoc h, JTextComponent  JavaDoc c) {
     Highlighter.HighlightPainter  JavaDoc painter = h.getPainter();
     String  JavaDoc painterClass = painter.getClass().getName();
     if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
             painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
         return false;
     }
     try {
         DefaultHighlighter.DefaultHighlightPainter  JavaDoc defPainter =
                 (DefaultHighlighter.DefaultHighlightPainter  JavaDoc) painter;
         if (defPainter.getColor() != null &&
                 !defPainter.getColor().equals(c.getSelectionColor())) {
             return false;
         }
     } catch (ClassCastException  JavaDoc e) {
         return false;
     }
     return true;
 }

So using the color depends on L&F and painter. If you define your onw painter the color won't be used.

Hoopes answered 1/10, 2013 at 5:26 Comment(2)
In my case, I am trying to get the color of the actual text to behave differently, not the color of the highlight. Like if I highlight two words, one word is black text the other is red text. When highlighted, I want the text color to display as the correct color and the highlight color to remain the same. But I haven't found any evidence that Java supports 2 different selected text colors, since there is a setSelectedText method that lets me change the selected text color to just one color, and no option for variable colors. Does that make sense?Bassist
Could you post SSCCE with different colors selected? For me you should replace the default HighlighPainter with your own where you paint not only background but also text fo selection with desired colors.Hoopes
A
3

It sounds like you may be using something other than a font family name. I re-factored this example to use JTextPane and saw the expected result. As noted there, the actions require a font family name, e.g. the default or face=SansSerif, as specified by the FontFamilyAction class nested in StyledEditorKit.

image

JTextPane textPane = new JTextPane();
Avocado answered 30/9, 2013 at 20:23 Comment(4)
I can recreate your above example using setSelectedText(Color). But my question is if Java supports having variable selected text colors, or if it only supports one. So if I selected 2 words, one black text and one red text, and I set the selected text color to red (setSelectedTextColor(Color.RED)) then both words would show up as red when highlighted, but I would like the black word to still display as black even when highlighted.Bassist
I'm not sure what you're trying to accomplish; the EditorKit actions are intended to operate on the selection, while still leaving the selection legible.Avocado
My issue with performing actions on the selected text, but rather with how the text displays when it is highlighted. In your example, the highlighted text shows up as red. But say in the original, unselected text "Stack" is red and "OverFlow" is black. When highlighted, it would still display as all red, like it does in your screenshot. So I'm wondering if there's a way to have the "OverFlow" part of the word still display as black when highlighted, and "Stack" still be red.Bassist
Not to my knowledge, but @StanislavL's idea seems worth pursuing.Avocado
O
0

Simplest way to change the color of selected Text :

int start = textPane.getSelectionStart();
int end = textPane.getSelectionEnd();
int selectedLength = end - start;
StyleDocument style = pane.getStyledDocument();

//this give your attribute set of selected Text. 
AttributeSet oldSet = style.getCharacterElement(end-1).getAttributes();

//StyleContext for creating attribute set
StyleContext sc = StyleContext.getDefaultStyleContext();

// Attribute set which contains new color with old attributes
AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Foreground, Color.RED);
//This set the color of the Text
style.setCharacterAttributes(start, selectedLength, s, true);
Orinasal answered 14/7, 2017 at 12:49 Comment(0)
L
0

Adding my view. This could be further simple then above approaches.

    JEditorPane ep = new JEditorPane() {
        @Override
        public Color getSelectionColor() {
            return COLOR_YOU_WANT;
        }

        @Override
        public Color getSelectedTextColor() {
            return COLOR_YOU_WANT;
        }
    };
Lithotrity answered 7/12, 2020 at 13:19 Comment(0)
H
0

I think you are after what I'm looking for here 9 years after your question; basically not to have a selectedTextColor. I've found the solution nowhere, but in my desperation I tried the following:

JTextPane thePane = ...;
thePane.setSelectedTextColor(null);

And it just works! Selected text has its background changed to selectionColor, but the text letters retain their original foreground color. I'm writing a custom code highlighter, hence I needed this to retain the highlights (applied through HTMLDocument spans with CSS class). It looks like this: JTextPane with selection retaining its foreground color

Instead of something like this: enter image description here

Husch answered 12/4, 2023 at 22:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.