在Java Swing中,我可以实时接收Caret事件吗?

我正在编写一个类似hex编辑器的视图,它由两个JTextComponents(hex和ASCII)组成。 我想同步两个视图之间的选择,所以我为这两个组件实现了一个CaretListener。 这适用于响应用户长按,拖动和释放鼠标的选择事件。 当用户释放鼠标时,组件会收到caretUpdate。

当用户按下鼠标并拖动鼠标而不释放时,组件如何接收增量的caretUpdate事件?

不幸的是,没有JTextArea选择模型,否则这将非常容易……

相反,我被迫在每个文本区域的Caret中添加一个ChangeListener 。 这让我可以看到实时更改插入位置的时间。

下一个问题发生在我意识到只有当前文本区域实际上会显示它的选择亮点….( nb这可以很容易地纠正,检查下一次更新

然后我不得不将荧光笔应用于未聚焦的文本区域……

在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.io.File; import java.io.FileReader; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; public class CaretTest { public static void main(String[] args) { new CaretTest(); } public CaretTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { setLayout(new GridLayout(1, 2)); JTextArea left = new JTextArea(10, 20); JTextArea right = new JTextArea(10, 20); left.setEditable(false); right.setEditable(false); left.getCaret().addChangeListener(new ChangeHandler(left, right)); right.getCaret().addChangeListener(new ChangeHandler(right, left)); left.addFocusListener(new FocusHandler(left, right)); right.addFocusListener(new FocusHandler(right, left)); JScrollPane leftSP = new JScrollPane(left); JScrollPane rightSP = new JScrollPane(right); leftSP.getHorizontalScrollBar().setModel(rightSP.getHorizontalScrollBar().getModel()); leftSP.getVerticalScrollBar().setModel(rightSP.getVerticalScrollBar().getModel()); add(leftSP); add(rightSP); FileReader reader = null; try { reader = new FileReader(new File("Ni.txt")); left.read(reader, null); reader.close(); reader = new FileReader(new File("Ni.txt")); right.read(reader, null); } catch (Exception exp) { exp.printStackTrace(); } finally { try { reader.close(); } catch (Exception e) { } } } protected void updateHighlighting(JTextArea source, JTextArea target) { DefaultHighlighter.DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(target.getSelectionColor()); int start = source.getSelectionStart(); int end = source.getSelectionEnd(); try { target.getHighlighter().addHighlight(start, end, painter); } catch (BadLocationException ex) { ex.printStackTrace(); } } public class ChangeHandler implements ChangeListener { private final JTextArea source; private final JTextArea target; public ChangeHandler(JTextArea source, JTextArea target) { this.source = source; this.target = target; } @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == source.getCaret()) { target.getHighlighter().removeAllHighlights(); updateHighlighting(source, target); } } } public class FocusHandler extends FocusAdapter { private final JTextArea source; private final JTextArea target; public FocusHandler(JTextArea source, JTextArea target) { this.source = source; this.target = target; } @Override public void focusGained(FocusEvent e) { source.getHighlighter().removeAllHighlights(); target.getHighlighter().removeAllHighlights(); updateHighlighting(source, target); } } } } 

ps-你需要提供自己的文字;)

使用“非荧光笔”示例进行更新

感谢StanislavL指出您可以使用JTextComponent#getCaret()#setSelectionVisible(true)来使非聚焦文本组件显示它的选定文本。

我确实发现焦点更改再次变为false ,所以我在更改处理程序中更新为始终为true

 import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.io.File; import java.io.FileReader; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; public class CaretTest { public static void main(String[] args) { new CaretTest(); } public CaretTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { setLayout(new GridLayout(1, 2)); JTextArea left = new JTextArea(10, 20); JTextArea right = new JTextArea(10, 20); left.setEditable(false); right.setEditable(false); left.getCaret().setSelectionVisible(true); right.getCaret().setSelectionVisible(true); left.getCaret().addChangeListener(new ChangeHandler(left, right)); right.getCaret().addChangeListener(new ChangeHandler(right, left)); JScrollPane leftSP = new JScrollPane(left); JScrollPane rightSP = new JScrollPane(right); leftSP.getHorizontalScrollBar().setModel(rightSP.getHorizontalScrollBar().getModel()); leftSP.getVerticalScrollBar().setModel(rightSP.getVerticalScrollBar().getModel()); add(leftSP); add(rightSP); FileReader reader = null; try { reader = new FileReader(new File("Ni.txt")); left.read(reader, null); reader.close(); reader = new FileReader(new File("Ni.txt")); right.read(reader, null); } catch (Exception exp) { exp.printStackTrace(); } finally { try { reader.close(); } catch (Exception e) { } } } } public static class ChangeHandler implements ChangeListener { private static boolean ignoreUpdates = false; private final JTextArea source; private final JTextArea target; public ChangeHandler(JTextArea source, JTextArea target) { this.source = source; this.target = target; } @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == source.getCaret()) { if (!ignoreUpdates) { ignoreUpdates = true; try { target.getCaret().setSelectionVisible(true); source.getCaret().setSelectionVisible(true); target.setSelectionStart(source.getSelectionStart()); target.setSelectionEnd(source.getSelectionEnd()); } finally { ignoreUpdates = false; } } } } } }