9

Now finishing my custom menu popup, but the problem is that if I select some text in JTextField and click mouse button to show popup menu, then focus is transferred to popup window, AND selected text before are no longer highlighted. When focus is back to JTextField - selected text become highlighted again. How to make the selected text stay highlighted on focus lost?

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Ernestas Gruodis
  • 8,567
  • 14
  • 55
  • 117
  • please see [my question for more details](http://stackoverflow.com/questions/18243101/how-to-override-defaultcaretsetblinkrate), better isn't it – mKorbel Aug 15 '13 at 06:40
  • related: https://stackoverflow.com/questions/5901833/text-selection-conflict-between-jtextpane-and-jtextfield/5911680#5911680 – Balder Jan 17 '22 at 07:22

1 Answers1

11

then focus is transferred to popup window, AND selected text before are no longer highlighted. When focus is back to JTextField - selected text become highlighted again. How to make the selected text stay highlighted on focus lost?

code example from DefaultCaret

class HighlightCaret extends DefaultCaret {

    private static final Highlighter.HighlightPainter unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
    private static final Highlighter.HighlightPainter focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
    private static final long serialVersionUID = 1L;
    private boolean isFocused;

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter() {
        return isFocused ? focusedPainter/*super.getSelectionPainter()*/ : unfocusedPainter;
    }

    @Override
    public void setSelectionVisible(boolean hasFocus) {
        if (hasFocus != isFocused) {
            isFocused = hasFocus;
            super.setSelectionVisible(false);
            super.setSelectionVisible(true);
        }
    }
}

with output

enter image description here

from code

import java.awt.*;
import javax.swing.*;
import javax.swing.text.DefaultCaret;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;

public class TestTextComponents {

    private static final long serialVersionUID = 1L;
    private JTextField jTextField1;
    private JTextField jTextField2;
    private JFrame frame = new JFrame("Default Caret");

    public TestTextComponents() {
        jTextField1 = new JTextField();
        jTextField2 = new JTextField();
        jTextField1.setText("jTextField1");
        jTextField2.setText("jTextField2");
        jTextField1.setCaret(new HighlightCaret());
        jTextField2.setCaret(new HighlightCaret());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLayout(new FlowLayout());
        frame.add(new JLabel("Please skip between text fields and watch persistent selection: "));
        frame.add(jTextField1);
        frame.add(jTextField2);
        frame.setTitle("Text component persistent selection");
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestTextComponents();
            }
        });
    }
}

class HighlightCaret extends DefaultCaret {

    private static final Highlighter.HighlightPainter unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
    private static final Highlighter.HighlightPainter focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
    private static final long serialVersionUID = 1L;
    private boolean isFocused;

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter() {
        setBlinkRate(500); // otherwise is disabled, stopped
        return isFocused ? focusedPainter/*super.getSelectionPainter()*/ : unfocusedPainter;
    }

    @Override
    public void setSelectionVisible(boolean hasFocus) {
        if (hasFocus != isFocused) {
            isFocused = hasFocus;
            super.setSelectionVisible(false);
            super.setSelectionVisible(true);
        }
    }
}

EDIT have to restore Caret.setBlinkRate(500);

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Wow, that simple, I'm impressed :) Thanks again indeed @mKorbel ! Problem solved in a few seconds :) – Ernestas Gruodis Aug 14 '13 at 16:48
  • @Ernestas Gruodis glad if help you – mKorbel Aug 14 '13 at 16:49
  • After I set `textField.setCaret(new HighlightCaret());` I noticed that caret stops blinking.. Maybe there is some setting in `Caret` class? Now trying to dig deeper in `DefaultCaret` class. – Ernestas Gruodis Aug 14 '13 at 17:09
  • 1
    Yes, like I expected - the `public HighlightCaret() { setBlinkRate(500); }` did the trick. Now caret blinks again :) – Ernestas Gruodis Aug 14 '13 at 17:24
  • test whats returns getBlinkRate(), but AFAIK this could be another reason to use JTextPane, there is cursor visible – mKorbel Aug 14 '13 at 17:25
  • The caret was present, but didn't blink. – Ernestas Gruodis Aug 14 '13 at 17:41
  • but hmmm now I see that Caret blinks on 3rd focusGained, no idea how to fix that – mKorbel Aug 14 '13 at 18:58
  • In the code above `setBlinkRate(500);` is placed in ` protected Highlighter.HighlightPainter getSelectionPainter()` method. I have place it in `HighlightCaret() { setBlinkRate(500); }`, so it is set only once. Not really understand what 3rd focusGained means.. – Ernestas Gruodis Aug 14 '13 at 19:18
  • 1
    got it, use most complete (you can to compare) [DefaultCaret](http://stackoverflow.com/a/5911680/714968) by @kleopatra – mKorbel Aug 14 '13 at 19:19
  • Found not much difference, except in `public void setSelectionVisible(boolean vis)` is `super.setSelectionVisible(!isSelectionVisible());`. Replaced it in my code, works the same, no problems. – Ernestas Gruodis Aug 14 '13 at 19:32
  • well agree with you, but still I'm not satisfied, I made there important changes and change L&F to Nimbus, then caret blinkind on 3rd. focusGained – mKorbel Aug 14 '13 at 19:37
  • I always trying to create my own L&F - like this popup menu from scratch - so always independent from L&F - less problems. – Ernestas Gruodis Aug 14 '13 at 20:15
  • It works almost... however, when I tab out of a component, it sometimes retains its yellow color. This is with default L&F (Metal). http://tinybrain.de/1008677 Same result with Substance L&F. http://tinybrain.de/1008678 – Stefan Reich May 28 '17 at 05:07
  • Also I would love a solution where the selection is visible even when the text field has never been in focus (I preselect text through the program). – Stefan Reich May 28 '17 at 05:31