Могу ли я получать события Caret в режиме реального времени в Java Swing?
Я пишу шестнадцатеричное редакторское представление, которое состоит из двух JTextComponents (hex и ASCII). Я хотел бы синхронизировать выбор между двумя представлениями, поэтому я реализовал CaretListener для двух компонентов. Это хорошо работает для реагирования на события выбора, когда пользователь долго нажимал, тащил и отпускал мышь. Компоненты получают значение caretUpdate, когда пользователь отпускает мышь.
Как компоненты могут получать инкрементные события caretUpdate, когда пользователь нажимает мышь и перемещает мышь, не отпуская ее?
1 ответ
К сожалению, нет модели выбора для JTextArea
иначе это было бы очень легко...
Вместо этого я был вынужден добавить ChangeListener
к Caret
каждой текстовой области. Это позволило мне увидеть, когда позиция каретки была изменена в режиме реального времени.
Следующая проблема возникла, когда я понял, что только текущая текстовая область будет отображать выделение выделенной области.... (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;
}
}
}
}
}
}