4

Let's say we have two JTextArea in a JPanel, I want the user to be able to select text cross these two JTextArea using mouse in one select, Is it possible in Swing?

Regards

so far I have tried:

I tried add mouselistener to these JTextArea, when mouseEnter, I select text in that TextArea, and highlight the text, pragmatically. This is both hard and error prone, I think maybe there is a better way

EDIT:

Thanks for all the answers and suggestions. Based on the answers, I implemented a basic solution and put it as an answer for other's reference. :)

didxga
  • 5,935
  • 4
  • 43
  • 58
  • 1
    Is it possible? Sure, anything is possible. What have you tried? – Kevin Workman Mar 05 '14 at 14:54
  • @KevinWorkman I tried add mouselistener to these JTextArea, when mouseEnter, I select text in that TextArea, and highlight the text, pragmatically. This is both hard and error prone, I think maybe there is a better way – didxga Mar 05 '14 at 14:57
  • You'll probably have to extend JTextArea and remember the last selected text in the non active component, when you copy on the other component, then cat the two selected texts together. Trick is knowing when the user copied, not sure if you can easily pick up on that if they just control-c'ed. – NESPowerGlove Mar 05 '14 at 14:58
  • @NESPowerGlove yes, but the problem is I want the user see the text was selected cross these two textarea visually, that is the text in the first textarea remain selected (text is in hightlight), when user is selecting text in the second one – didxga Mar 05 '14 at 15:01

4 Answers4

5

that is the text in the first textarea remain selected (text is in hightlight), when user is selecting text in the second one

I assume you mean the user is selecting different pieces of text in the two different text areas.

By default text components only show the selected text when the text component has focus.

The simple answer is to create a custom Caret and override the focusLost(...) method and invoke setSelectionVisible(true) at the end of the method to make sure the selection is painted even when the text component doesn't have focus.

Here is a fancier version of that approach that will allow you to specify a different selection background Color for the text component that doesn't have focus (if you wish):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class SelectionCaret extends DefaultCaret
{
    private static final Color SELECTION_COLOR = UIManager.getColor("TextField.selectionBackground");

    private Highlighter.HighlightPainter focusedPainter;
    private Highlighter.HighlightPainter unfocusedPainter;

    public SelectionCaret()
    {
        this(SELECTION_COLOR);
    }

    public SelectionCaret(Color unfocusedColor)
    {
        focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(SELECTION_COLOR);
        unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(unfocusedColor);

        setBlinkRate( UIManager.getInt("TextField.caretBlinkRate") );
    }

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter()
    {
        return getComponent().hasFocus() ? focusedPainter : unfocusedPainter;
    }

    @Override
    public void focusGained(FocusEvent e)
    {
        setSelectionVisible(false);
        super.focusGained(e);
    }

    @Override
    public void focusLost(FocusEvent e)
    {
        super.focusLost(e);
        setSelectionVisible(true);
    }

    private static void createAndShowUI()
    {
        JTextField textField1 = new JTextField("Text Field1   ");
        JTextField textField2 = new JTextField("Text Field2   ");
        JTextField textField3 = new JTextField("Non Editable   ");
        textField3.setEditable(false);

        textField1.setCaret(new SelectionCaret());
        textField2.setCaret(new SelectionCaret());
        textField3.setCaret(new SelectionCaret());

        textField1.select(5, 11);
        textField2.select(5, 11);
        textField3.select(5, 11);
        ((DefaultCaret)textField1.getCaret()).setSelectionVisible(true);
        ((DefaultCaret)textField2.getCaret()).setSelectionVisible(true);
        ((DefaultCaret)textField3.getCaret()).setSelectionVisible(true);

        JPanel north = new JPanel();
        north.add( new JTextField("Text Field0   ") );
        north.add(textField1);
        north.add(textField2);
        north.add(textField3);

        JFrame frame = new JFrame("Selection Caret");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( north );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

The above code was based on the code provided by mKorbel in this posting.

Community
  • 1
  • 1
camickr
  • 321,443
  • 19
  • 166
  • 288
  • Actually what I wanted is selecting text in different component at once, meaning select across components at one mouse select. – didxga Dec 15 '17 at 15:16
  • I implement solution based on your code though, post the answer myself – didxga Dec 15 '17 at 16:25
2

Probably you will have to work registering an event handler in one JTextArea, maybe there is one specific for the kind of event that belong to text selection, and then programmatically propagate the same effect on the other JTextArea. But there is no more magic beyond that.

For the event type you are looking, look forward the keywords: Swing JTextArea event listener for text selection

If my memory doesn fail, there the JTextField cames with a method for selecting the text in a range.

For this kind of problem, look for : Selecting text in jTextField

I thing that this way i'll strike the problem.

Hope it helps!!

Greetings!.

Community
  • 1
  • 1
Victor
  • 3,841
  • 2
  • 37
  • 63
1

Usong Swing normally, you can't. It is not design to allow selection in two different focusable objects. However, You can bend it to do it using MouseListeners and the select(int,int) method in JTextComponent. But be warned, it might be tricky.

Another solution would be to use only one real JTextComponent and divide it graphically by painting a separating bar on it or whatever you see fit.

Hope it help!

frenchfrie
  • 111
  • 6
0

Based on @camickr's answer and code, I implement a rudimentary solution (this achieved my goal, although far from optimized, you must refactor the code when you want to use it):

public class SelectionCaret extends DefaultCaret
{

    private static boolean isselecting = false;

    private static final Color SELECTION_COLOR = UIManager.getColor("TextField.selectionBackground");

    private Highlighter.HighlightPainter focusedPainter;
    private Highlighter.HighlightPainter unfocusedPainter;

    public SelectionCaret()
    {
        this(SELECTION_COLOR);
    }

    public SelectionCaret(Color unfocusedColor)
    {
        focusedPainter = new DefaultHighlighter.DefaultHighlightPainter(SELECTION_COLOR);
        unfocusedPainter = new DefaultHighlighter.DefaultHighlightPainter(unfocusedColor);

        setBlinkRate( UIManager.getInt("TextField.caretBlinkRate") );
    }

    @Override
    protected Highlighter.HighlightPainter getSelectionPainter()
    {
        return getComponent().hasFocus() ? focusedPainter : unfocusedPainter;
    }

    @Override
    public void focusGained(FocusEvent e)
    {
        setSelectionVisible(false);
        super.focusGained(e);
    }

    @Override
    public void focusLost(FocusEvent e)
    {
        super.focusLost(e);
        setSelectionVisible(true);
    }

    private static void createAndShowUI()
    {
        JTextField textField1 = new JTextField("Text Field1   ");
        JTextField textField2 = new JTextField("Text Field2   ");

        textField1.setCaret(new SelectionCaret());
        textField2.setCaret(new SelectionCaret());

        ((DefaultCaret)textField1.getCaret()).setSelectionVisible(true);
        ((DefaultCaret)textField2.getCaret()).setSelectionVisible(true);

        JPanel north = new JPanel();
        north.add(textField1);
        north.add(textField2);

        JFrame frame = new JFrame("Selection Caret");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( north );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );

        north.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {

            }

            @Override
            public void mousePressed(MouseEvent e) {
                SelectionCaret.isselecting = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                SelectionCaret.isselecting = false;
            }

            @Override
            public void mouseEntered(MouseEvent e) {

            }

            @Override
            public void mouseExited(MouseEvent e) {

            }
        });

        textField1.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
            }

            @Override
            public void mousePressed(MouseEvent e) {
                SelectionCaret.isselecting = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                SelectionCaret.isselecting = false;
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if(SelectionCaret.isselecting) {
                    Robot robot = null;
                    try {
                        robot = new Robot();
                        robot.mousePress(InputEvent.BUTTON1_MASK);
                    } catch (AWTException e1) {
                        e1.printStackTrace();
                    }
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {

            }
        });

        textField2.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {

            }

            @Override
            public void mousePressed(MouseEvent e) {
                SelectionCaret.isselecting = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                SelectionCaret.isselecting = false;
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if(SelectionCaret.isselecting) {
                    Robot robot = null;
                    try {
                        robot = new Robot();
                        robot.mousePress(InputEvent.BUTTON1_MASK);
                    } catch (AWTException e1) {
                        e1.printStackTrace();
                    }
                }

            }

            @Override
            public void mouseExited(MouseEvent e) {

            }
        });
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
didxga
  • 5,935
  • 4
  • 43
  • 58