1

Why the text in JTextPane cannot be selected programmatically if there is a JTextField present? Has something to do with focus i think. Thx.

import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;

public class align extends JFrame  {

    private align() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        addPane(this, "one");
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        align t = new align();
    }

    private void addPane(JFrame frame, String name) {

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT));
        // if the next line is disabled, then the text is JTextPane is correctly highlighted.,,
        panel.add(makeField("line1"));

        JTextPane p = new JTextPane();
        p.setText("abcdef");
        p.setSelectionStart(2);
        p.setSelectionEnd(4);
        p.setFocusable(true);
        p.requestFocus();
        p.requestDefaultFocus();
        panel.add(p);

        frame.getContentPane().add(panel);
    }

    private JComponent makeField(String name) {
        JTextField textArea = new JTextField();
        textArea.setText(name);
        textArea.setEditable(false);

        return textArea;
    }
}

EDIT:

Got it to display the selected text by firing the key event after the frame has been built. A better (longer) solution would be to have a read-only TextPane with custom Highlighter and DocumentListener that keeps the clipboard updated on Ctrl-C.

    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
            new KeyEvent(textPane, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, KeyEvent.VK_TAB));
Saideira
  • 2,374
  • 6
  • 38
  • 49

4 Answers4

4

Just for fun (after all, it's Friday :-) I followed up Stanislav's comment, extending DefaultCaret to keep the selection visible for unfocused textComponents.

The basic ideas

  • support two selection decorations: focused-selection, unfocused-selection
  • keep the appearance of the selection highlights as near to LAF default as possible, which boils down to re-using the selectionPainter (accessible only by ... cough, cough .. reflection)
  • fool super into believing that the selection is always visible

    public static class WrappingCaret extends DefaultCaret {
    
        private DefaultCaret delegate;
        private HighlightPainter focusedSelectionPainter;
        private HighlightPainter unfocusedSelectionPainter;
        private boolean focusedSelectionVisible;
    
        public WrappingCaret(JTextComponent target) {
            installDelegate((DefaultCaret) target.getCaret());
            target.setCaret(this);
        }
    
        private void installDelegate(DefaultCaret delegate) {
            this.delegate = delegate;
            setBlinkRate(delegate.getBlinkRate());
        }
    
        private void installSelectionPainters() {
            if (delegate instanceof BasicCaret) {
                installDefaultPainters();
            } else {
                try {
                    Method method = delegate.getClass().getDeclaredMethod(
                            "getSelectionPainter");
                    method.setAccessible(true);
                    focusedSelectionPainter = (HighlightPainter) method
                            .invoke(delegate);
                    Constructor<?>[] constructors = focusedSelectionPainter
                            .getClass().getDeclaredConstructors();
                    constructors[0].setAccessible(true);
                    unfocusedSelectionPainter = (HighlightPainter) constructors[0]
                            .newInstance(getUnfocusedSelectionColor());
                } catch (Exception e) {
                    installDefaultPainters();
                }
            }
        }
    
        private Color getUnfocusedSelectionColor() {
            Color first = getComponent().getSelectionColor();
            // create a reasonable unfocusedSelectionColor
            return PaintUtils.setAlpha(first, 125);
        }
    
        private void installDefaultPainters() {
            focusedSelectionPainter = super.getSelectionPainter();
            unfocusedSelectionPainter = new DefaultHighlightPainter(
                    getUnfocusedSelectionColor());
        }
    
        /**
         * @inherited <p>
         */
        @Override
        public void install(JTextComponent c) {
            super.install(c);
            installSelectionPainters();
            setSelectionVisible(isSelectionVisible());
        }
    
        /**
         * @inherited <p>
         */
        @Override
        public void setSelectionVisible(boolean vis) {
            focusedSelectionVisible = vis;
            super.setSelectionVisible(!isSelectionVisible());
            super.setSelectionVisible(true);
        }
    
        /**
         * @inherited <p>
         */
        @Override
        protected HighlightPainter getSelectionPainter() {
            return focusedSelectionVisible ? focusedSelectionPainter
                    : unfocusedSelectionPainter;
        }
    
    }
    

Enjoy!

kleopatra
  • 51,061
  • 28
  • 99
  • 211
3

The text in the JTextPane is selected. The trouble is that it does not give any visual indication unless the component is focused. Try tabbing to the component once the GUI is shown.


so, i should release note this?

No, you should redesign your broken GUI that uses text selection to identify text of interest. Text selection is more something for the end user to do, not the application.

Given JTextPane is a component that supports formatting, possibly make the text bold or italic for instance.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
3

Maybe you should be using a Highlighter so the highlighting appears in all text components:

Highlighter.HighlightPainter yellow = 
    new DefaultHighlighter.DefaultHighlightPainter( Color.YELLOW );

try
{
    textPane.getHighlighter().addHighlight(2, 4, yellow);
}
catch(BadLocationException ble) { System.out.println(ble); }
camickr
  • 321,443
  • 19
  • 166
  • 288
  • Clever approach. Hate the color though. ;) – Andrew Thompson May 05 '11 at 18:36
  • Yes that would work if i need highlighting for cosmetic purposes. I need real select for clipboard functionality. – Saideira May 05 '11 at 19:59
  • 1
    @Saideira, Then you only need to display one selection at a time because the copy functionality to the clipboard only works on the component that has focus. So this is not an issue. – camickr May 05 '11 at 21:15
  • @camickr - Rob, what do mean by your comment? textComponent.copy works always, focused or not. As you know that, I'm probably missing something :-) – kleopatra May 06 '11 at 09:26
  • 1
    @kleopatra - Jeanette, bad wording on my part:) the poster was complaining that that selection would not show on two components at the same time. I was trying to imply that having a selection show on two components would be confusing because you would only be able to copy from the component that had focus. Of course if neither text component had focus then the copy would be done on the last component that had focus. But again this would be confusing since the user might think that the text from both components should be copied. I was suggesting not to have two components with selected text. – camickr May 06 '11 at 15:11
  • ahh ... thanks for the clarification! yeah, valid point - the unfocusedSelection color should be different enough from the focusedSelection color – kleopatra May 06 '11 at 15:17
3
p.getCaret().setSelectionVisible(true);
StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • only, how to keep it that way? once the pane went through a focusGained/-Lost, the selection visibility is gone again. Hmm ... – kleopatra May 06 '11 at 07:57
  • right. The selection is set to false when focus is lost but it's possible to use own caret e.g. extend DefaultCaret and override the logic. – StanislavL May 06 '11 at 08:13
  • ahh .. I see, had misunderstood the semantics of the setSelectionVisible, it's the actual toggle of showing/hiding the selection highlight (vs. I understood it as a property to keep it visible always). Hmm .. maybe the real issue is a missing unfocused-selection highlight? Could be implemented in a custom caret .. always felt it strange to loose visual selection hints, unusual in win at least – kleopatra May 06 '11 at 09:15