4

I want to use a JTextArea or JTextPane as a code change player, and the code changes and caret movements are recorded in a text file. But the problem is, it's recorded from an editor which supports multi selection, so there are more than one caret positions at one time.

Is it possible to show multiple carets in JTextArea or JTextPane?

I tried to use JTextPane and render the code as HTML, and inserted some <span class='caret'>|</span> into the code to represent the carets, it works but the fake caret takes space, so the normal characters are not fixed on screen when caret changes.

Freewind
  • 193,756
  • 157
  • 432
  • 708

2 Answers2

5

Like this?

import javax.swing.*;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import java.awt.*;
import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        JFrame fr=new JFrame("Multi caret test");
        JTextArea ta=new JTextArea("Test test test", 20, 40);
        MultiCaret c=new MultiCaret();
        c.setBlinkRate(500);
        c.setAdditionalDots(Arrays.asList(2,4,7));
        ta.setCaret(c);
        fr.add(ta);

        fr.pack();
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fr.setLocationRelativeTo(null);
        fr.setVisible(true);
    }
}

class MultiCaret extends DefaultCaret {
    private List<Integer> additionalDots;

    public void setAdditionalDots(List<Integer> additionalDots) {
        this.additionalDots = additionalDots;
    }

    public void paint(Graphics g) {
        super.paint(g);

        try {
            TextUI mapper = getComponent().getUI();
            for (Integer addDot : additionalDots) {
                Rectangle r = mapper.modelToView(getComponent(), addDot, getDotBias());

                if(isVisible()) {
                    g.setColor(getComponent().getCaretColor());
                    int paintWidth = 1;
                    r.x -= paintWidth >> 1;
                    g.fillRect(r.x, r.y, paintWidth, r.height);
                }
                else {
                    getComponent().repaint(r);
                }
            }
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

}
StanislavL
  • 56,971
  • 9
  • 68
  • 98
2

an editor which supports multi selection,

Maybe you should be using a Highlighter to highlight multiple areas of text selection:

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

public class TextAndNewLinesTest extends JFrame
{
    public TextAndNewLinesTest()
        throws Exception
    {
        String text =
            "one two three four five\r\n" +
            "one two three four five\r\n" +
            "one two three four five\r\n" +
            "one two three four five\r\n" +
            "one two three four five\r\n";

        JTextPane textPane = new JTextPane();
        textPane.setText(text);
        JScrollPane scrollPane = new JScrollPane( textPane );
        getContentPane().add( scrollPane );

        Highlighter.HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter( Color.cyan );

        String search = "three";
        int offset = 0;

        int length = textPane.getDocument().getLength();
        text = textPane.getDocument().getText(0, length);

        while ((offset = text.indexOf(search, offset)) != -1)
        {
            try
            {
                textPane.getHighlighter().addHighlight(offset, offset + 5, painter); // background
                offset += search.length();
            }
            catch(BadLocationException ble) {}
        }
    }

    public static void main(String[] args)
        throws Exception
    {
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new TextAndNewLinesTest();
        frame.setTitle("Text and New Lines - Problem");
//      frame.setTitle("Text and New Lines - Fixed");
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.setSize(400, 120);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288