開いているさまざまなファイルを循環できるようにすると がJTextArea
あります。別のファイルを選択すると、内容が変化します。ファイルごとに異なる Undo バッファを維持しようとしており、ファイルごとに別のバッファを定義しました。JComboBox
JTextArea
UndoManager
私は、「One」と「Two」と呼ぶ 2 つのバッファーを使用して問題を示すための、より単純な SSCCE を作成しました。それらを切り替えるための単純なボタンがあります。がUndoableEdit
発生すると、アクティブなバッファをチェックaddEdit()
し、それぞれに対して を実行しますUndoManager
。「元に戻す」ボタンが押されると、それぞれの をチェックcanUndo()
して実行します。と呼ばれるフラグがあります。これは、バッファーを切り替えて、それらの編集が記録されないようにするときに使用されます。undo()
UndoManager
ignoreEdit
バッファーを切り替えなければ問題はありません。Undo は期待どおりに機能します。バッファを切り替えてドキュメントを「壊す」ように見える場合にのみ、失敗します。次の手順を使用して、問題を再現できます。
バッファ「One」に、次のように入力します。
THIS
IS ONE
EXAMPLE
バッファ「Two」に切り替えて、次のように入力します。
THIS
IS ANOTHER
EXAMPLE
バッファ「One」に切り替え、「元に戻す」ボタンを複数回押します。元に戻す操作を数回行った後、バッファは次のようになります (カーソルが最初の 2 行を選択する方法はありません)。しかし、 の内容は のtextArea.getText()
とおり正しいSystem.out.println()
ので、レンダリングの問題のように見えますか?
THIS
THISIS ONE
誰かがファイルごとに独立した Undo バッファを実装しようとしたのはこれが初めてではないでしょうか? 私は明らかに Document モデルで何か間違ったことをしており、本質的にそれを壊していますが、これを修正する最善の方法についてアドバイスを探していますか?
SSCCE のコードは次のとおりです。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
public class SSCCE extends JFrame implements ActionListener, UndoableEditListener {
private final JLabel labTextArea;
private final JTextArea textArea;
private final JScrollPane scrollTextArea;
private final Document docTextArea;
private final JButton bOne, bTwo, bUndo;
private final UndoManager uOne, uTwo;
private String sOne, sTwo;
private boolean ignoreEdit = false;
public SSCCE(String[] args) {
setTitle("SSCCE - Short, Self Contained, Correct Example");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
labTextArea = new JLabel("One");
getContentPane().add(labTextArea, BorderLayout.PAGE_START);
uOne = new UndoManager();
uTwo = new UndoManager();
sOne = new String();
sTwo = new String();
textArea = new JTextArea();
docTextArea = textArea.getDocument();
docTextArea.addUndoableEditListener(this);
scrollTextArea = new JScrollPane(textArea);
getContentPane().add(scrollTextArea, BorderLayout.CENTER);
JPanel pButtons = new JPanel();
bOne = new JButton("One");
bOne.addActionListener(this);
bOne.setFocusable(false);
pButtons.add(bOne, BorderLayout.LINE_START);
bTwo = new JButton("Two");
bTwo.addActionListener(this);
bTwo.setFocusable(false);
pButtons.add(bTwo, BorderLayout.LINE_END);
bUndo = new JButton("Undo");
bUndo.addActionListener(this);
bUndo.setFocusable(false);
pButtons.add(bUndo, BorderLayout.LINE_END);
getContentPane().add(pButtons, BorderLayout.PAGE_END);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(bOne)) {
if (!labTextArea.getText().equals("One")) {
sTwo = textArea.getText();
ignoreEdit = true;
textArea.setText(sOne);
ignoreEdit = false;
labTextArea.setText("One");
}
}
else if (e.getSource().equals(bTwo)) {
if (!labTextArea.getText().equals("Two")) {
sOne = textArea.getText();
ignoreEdit = true;
textArea.setText(sTwo);
ignoreEdit = false;
labTextArea.setText("Two");
}
}
else if (e.getSource().equals(bUndo)) {
if (labTextArea.getText().equals("One")) {
try {
if (uOne.canUndo()) {
System.out.println("Performing Undo for One");
uOne.undo();
System.out.println("Buffer One is now:\n" + textArea.getText() + "\n");
}
else {
System.out.println("Nothing to Undo for One");
}
}
catch (CannotUndoException ex) {
ex.printStackTrace();
}
}
else if (labTextArea.getText().equals("Two")) {
try {
if (uTwo.canUndo()) {
System.out.println("Performing Undo for Two");
uTwo.undo();
System.out.println("Buffer Two is now:\n" + textArea.getText() + "\n");
}
else {
System.out.println("Nothing to Undo for Two");
}
}
catch (CannotUndoException ex) {
ex.printStackTrace();
}
}
}
}
@Override
public void undoableEditHappened(UndoableEditEvent e) {
if (!ignoreEdit) {
if (labTextArea.getText().equals("One")) {
System.out.println("Adding Edit for One");
uOne.addEdit(e.getEdit());
}
else if (labTextArea.getText().equals("Two")) {
System.out.println("Adding Edit for Two");
uTwo.addEdit(e.getEdit());
}
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SSCCE(args);
}
});
}
}