Introduction
Sometimes, we need to find the exact location of the cursor (caret) in a text field or another similar control. Java provides us a set of methods to calculate it but, let’s be honest, who wants to waste a few minutes that can become days in calculating the caret position?
Back in time, about four or five days ago, I lost part of my hair and patience looking for a way to get the caret position in a JTextArea
. One way was to do it with the Windows API but it’ll finish in a Windows dependent program. Another way was to calculate the current column from the offset of the current cursor position. It works but not fully, at least not for my purposes. Looking in books, internet and asking my teachers at school how to determine the caret position, I got no answers. Finally, I found the way to do it: Use the method getMagicCaretPosition()
to get a Point structure with the actual position of the caret in the control.
Quick Start
As Oracle says in its Wiki, getMagicCaretPosition()
gets the current caret visual location. The caret changes its position every time we write or delete a character in the control. My first error was to say ”It shouldn’t be a problem, I just need to acquire the caret position when the text changes (in the method changeUpdate(KeyEvent evt)
included in DocumentListener
interface at javax.swing.event
)”. Why? Because when we write or delete a character in the control, the caret moves until the character is written or deleted. So, getting the caret position must be in the keyReleased
event to avoid getting a null
when calling the getMagicCaretPosition()
.
Using the Code
To see a little example, let’s make a Java project in NetBeans (7.4), add a new JFrame
to the package and a JTextArea
to the window. Then, implement the DocumentListener
and KeyListener
interfaces in the JFrame
.
public class getMagicCaretPositionGUI extends JFrame implements DocumentListener, KeyListener{...}
Of course, we must override the methods included in the implemented interfaces and subscribe the JTextArea
to the listeners.
public getMagicCaretPositionGUI() {
initComponents();
this.jTextArea1.addKeyListener(this);
this.jTextArea1.getDocument().addDocumentListener(this);
}
@Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void changedUpdate(DocumentEvent e) { }
@Override
public void keyTyped(KeyEvent e) { }
@Override
public void keyPressed(KeyEvent e) { }
@Override
public void keyReleased(KeyEvent e) { }
Focus on the changedUpdate(DocumentEvent e)
method, let’s see what happens when we try to get the current position at this method.
@Override
public void changedUpdate(DocumentEvent e) {
Point p = this.jTextArea1.getCaret().getMagicCaretPosition();
setTitle(”Actual caret position : X: ” + p. x + ” , Y: ” + p. y);
}
If we execute the project now, every time the text on the JTextArea
changes will throw an exception like Exception in thread ”AWT- EventQueue-0” java.lang.NullPointerException...
. Remember, when the document changes, the caret ”disappears” until the character is written or deleted.
It must be really hard to get it at the first time (as I, expend 3 days of my life getting this). Comment the code in insertUpdate
and removeUpdate
; and move the code in changedUpdate
to KeyReleased
and try it again.
@Override
public void keyReleased(KeyEvent e) {
Point p = this.jTextArea1.getCaret().getMagicCaretPosition();
this.setTitle("Actual caret position: X:" + p.x + ", Y: " + p.y);
}
Now it works pretty good. Beautiful, isn’t it?
Points of Interest
Getting the caret position in the changedUpdate
method is valid but you must set the caret position to 0,0 getting first the caret of the control in the constructor and setting the position with the method setMagicCaretPosition(Point p)
like this:
this.jTextArea1.getCaret().setMagicCaretPosition(new Point(0, 0));
I discovered it 10 minutes before uploading.