JTextField:获取鼠标按下前的光标位置
问题描述
给JTextField添加了MouseListener,需要获取鼠标按下前的光标位置,但监听器触发时光标位置已改变,且无法设置监听器优先级让其在光标改变前执行。添加CaretListener也无效,因为它仅在鼠标松开时触发。运行以下代码可复现问题:
package test; import java.awt.EventQueue; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; @SuppressWarnings("serial") public class TestCaret extends JFrame { public TestCaret() { JTextField text; TestListener listener; text = new JTextField("This is my text"); listener = new TestListener(); text.addMouseListener(listener); text.addCaretListener(listener); add(text); setDefaultCloseOperation(EXIT_ON_CLOSE); } private class TestListener extends MouseAdapter implements CaretListener { @Override public void caretUpdate(CaretEvent e) { System.out.println("Got CaretEvent " + e); } @Override public void mousePressed(MouseEvent e) { JTextField textField; textField = (JTextField)e.getComponent(); System.out.println("Got MouseEvent with caret position " + textField.getCaretPosition()); } } public static void main(String[] args) { Runnable runner; runner = new Runnable() { @Override public void run() { TestCaret frame; frame = new TestCaret(); frame.pack(); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } } // class TestCaret
解决建议
方案1:自定义JTextField拦截鼠标事件
核心思路是在JTextField默认处理鼠标按下事件(即改变光标位置)之前,先记录当前光标位置,通过重写processMouseEvent方法实现:
public class CustomTextField extends JTextField { private int prePressCaretPosition; public CustomTextField(String text) { super(text); } @Override protected void processMouseEvent(MouseEvent e) { // 仅在鼠标按下事件触发时记录光标位置 if (e.getID() == MouseEvent.MOUSE_PRESSED) { prePressCaretPosition = getCaretPosition(); } // 调用父类方法,执行默认的光标位置更新逻辑 super.processMouseEvent(e); } // 提供获取鼠标按下前光标位置的方法 public int getPrePressCaretPosition() { return prePressCaretPosition; } }
使用时替换原JTextField为CustomTextField,在MouseListener中调用getPrePressCaretPosition()即可拿到目标位置:
@Override public void mousePressed(MouseEvent e) { CustomTextField textField = (CustomTextField)e.getComponent(); System.out.println("鼠标按下前的光标位置:" + textField.getPrePressCaretPosition()); System.out.println("当前光标位置:" + textField.getCaretPosition()); }
方案2:维护全局光标位置变量
通过CaretListener实时记录当前光标位置(CaretEvent会在光标每次改变时触发),在鼠标按下事件中直接调用记录的历史位置:
private class TestListener extends MouseAdapter implements CaretListener { private int lastCaretPosition; @Override public void caretUpdate(CaretEvent e) { lastCaretPosition = ((JTextField)e.getSource()).getCaretPosition(); System.out.println("Got CaretEvent " + e); } @Override public void mousePressed(MouseEvent e) { JTextField textField = (JTextField)e.getComponent(); // lastCaretPosition 即为鼠标按下前的光标位置 System.out.println("鼠标按下前的光标位置:" + lastCaretPosition); System.out.println("当前光标位置:" + textField.getCaretPosition()); } }
注意:需确保CaretListener在程序启动时就已注册,否则初始光标位置无法被记录。
内容的提问来源于stack exchange,提问作者Robert Kock
相关产品推荐
相关产品推荐

