gpt4 book ai didi

java - 使用具有多个 UndoManagers 的单个 JTextArea

转载 作者:行者123 更新时间:2023-11-30 11:18:19 26 4
gpt4 key购买 nike

我有一个 JTextArea 和一个 JComboBox 允许我循环浏览各种打开的文件 - JTextArea 的内容随着我的选择而改变一个不同的文件。我试图为每个文件维护一个不同的撤消缓冲区,并为每个文件定义了一个单独的 UndoManager

我已经创建了一个更简单的 SSCCE 来使用两个缓冲区来演示我的问题,我称之为“一个”和“两个”——用一个简单的按钮在它们之间切换。一旦 UndoableEdit 发生,它会检查 Activity 缓冲区并在相应的 UndoManager 上执行 addEdit()。当按下“撤消”按钮时,它会检查 canUndo() 并在相应的 UndoManager 上执行 undo()。我有一个名为 ignoreEdit 的标志,在缓冲区之间切换时使用它来忽略记录的那些编辑。

如果我从不在缓冲区之间切换,那么我没有问题,撤消按预期工作。只有当我在缓冲区之间切换并且似乎“破坏”了文档时,它才会失败。可以使用以下步骤来重现问题:

在缓冲区“一”中,键入:

THIS
IS ONE
EXAMPLE

切换到缓冲区“二”,输入:

THIS
IS ANOTHER
EXAMPLE

切换到缓冲区“一”并多次按下“撤消”按钮。几次撤消操作后,缓冲区看起来像这样(光标无法选择前两行)。但是,根据 System.out.println()textArea.getText() 的内容是正确的 - 所以,它看起来像一个渲染问题?

THIS

THISIS ONE

这不是第一次有人尝试为每个文件实现独立的撤消缓冲区吗?很明显,我在文档模型上做错了事情,并且在本质上破坏了它,但我正在寻找一些关于如何最好地解决这个问题的建议?

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);
}
});
}
}

最佳答案

之前我曾尝试创建一个新的 Document 实例类(每个都引用相同的撤消监听器)并打算使用 JTextArea.setDocument()而不是 JTextArea.setText() .然而,Document是一个接口(interface),无法实例化,但在阅读了 mKorbel 发布的引用资料后,我尝试使用 PlainDocument改为上课,这很有效。

我决定维护一个 HashMap<String, Document>包含我的 Document类并在它们之间切换。当我切换 Document ,我没有看到撤消/重做问题 - 我想因为我不再打破 Document .

更新了下面的 SSCCE,现在使用 JTextArea.setDocument()而不是 JTextArea.setText() .这也有不需要 ignoreEdit 的优点 boolean 值 setDocument()不会触发 UndoableEditEvent ,而 setText()做。每个Document然后引用本地类 UndoableEditListener .

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 Document dOne, dTwo;

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();
dOne = new PlainDocument();
dTwo = new PlainDocument();
dOne.addUndoableEditListener(this);
dTwo.addUndoableEditListener(this);

textArea = new JTextArea();
docTextArea = textArea.getDocument();
docTextArea.addUndoableEditListener(this);
textArea.setDocument(dOne);
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")) {
textArea.setDocument(dOne);
labTextArea.setText("One");
}
}
else if (e.getSource().equals(bTwo)) {
if (!labTextArea.getText().equals("Two")) {
textArea.setDocument(dTwo);
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 (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);
}
});
}
}

关于java - 使用具有多个 UndoManagers 的单个 JTextArea,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23883050/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com