我正在编写一个类似于十六进制编辑器的 View ,它由两个 JTextComponents(十六进制和 ASCII)组成。我想同步两个 View 之间的选择,所以我为这两个组件实现了 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;
}
}
}
}
}
}
关于java - 在 Java Swing 中,我可以实时接收 Caret 事件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18199593/