从另一个 JtextArea 实时更新一个 JtextArea
Live updating one JtextArea from another JtextArea
我正在尝试编写一个程序来显示两个 Jtextareas,这两个都是可编辑的。目标是当您编辑 textAreaRom(输入罗马数字)时,第二个区域 (textAreaArab) 将显示等效的阿拉伯数字。但问题是我无法让这件事实时发生。我已经阅读过有关使用 DocumentListeners 的信息,但是,这是我第一次进行 GUI 编程,我不确定我将如何实现它。什么都有帮助。我是 GUI 和 Whosebug 的新手,所以请多多关照!
注意:我的转换方法都很完美。
public class ArabicToRomanGUI_Hard extends JFrame
{
private static final long serialVersionUID = 1L;
private static String input = "";
private static String output = "";
//constructor to add text fields to frame
public ArabicToRomanGUI_Hard()
{
//JFrame frame = new JFrame("Convert Back And Forth");
final JTextField enterRomNumber = new JTextField(20);
final JTextArea textAreaRom = new JTextArea(20,20);
final JTextField enterArabNumber = new JTextField(20);
final JTextArea textAreaArab = new JTextArea(20,20);
setLayout(new FlowLayout());
enterRomNumber.setText("Please enter a Roman numeral");
enterArabNumber.setText("Please enter a Arabic Number");
textAreaRom.setEditable(true);
textAreaArab.setEditable(true);
//textAreaRom.setText(enterRomNumber.getText());
//textAreaArab.setText(enterArabNumber.getText());
if(textAreaRom.isFocusOwner() == true)
{
textAreaRom.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
{
e.getKeyChar();
input += e.getKeyChar();
ConversionLogic_Hard.ConvertFromRomanToArabic(input); //convert
ConversionLogic_Hard.getCheckFail(); //check if conversion is valid.
output = ConversionLogic_Hard.getConvertedRomanNumeral(); //get the conversion
while(ConversionLogic_Hard.getCheckFail() == true && textAreaArab.isFocusOwner() == false)
{
textAreaArab.setText(output);
}
textAreaArab.setText(input);
}
}
});
}
getContentPane().add(enterRomNumber, BorderLayout.EAST);
getContentPane().add(textAreaRom, BorderLayout.WEST);
}
你其实有3个问题...
- 在更新第一个文本组件时更新第二个文本组件,这相对容易。
- 在更新第二个文本组件时更新第一个文本组件...好吧,这变得非常复杂非常快。
- 过滤输入的文本。 Implementing a Document Filter
这实际上相对容易
现在,真正的问题是#2,这是因为当第一个字段试图更新第二个字段时,您可能很快就会陷入一个令人讨厌的地方,这会触发和事件导致第二个字段更新触发第一个字段和导致第一个字段更新第二个字段的事件......你开始明白了。
幸运的是,Swing 实际上不会让它变得那么糟糕,并且会抛出 IllegalStateException
为了克服这个问题,你需要有某种方法来知道什么时候对 Document
的更新是由从属字段触发的,或者它是由其他东西触发的(比如 setText
被调用,用户在字段中键入或粘贴文本)并忽略其中一些事件
现在,可能有一种非常酷且简单的方法可以做到这一点,但我的大脑今天不在 "simple" 模式,抱歉。
所以,我从自定义 Document
开始,它基本上有一个允许我检查其状态的标志
public class MirrorDocument extends PlainDocument {
private boolean ignoreUpdates;
public void setIgnoreUpdates(boolean ignoreUpdates) {
this.ignoreUpdates = ignoreUpdates;
}
public boolean isIgnoreUpdates() {
return ignoreUpdates;
}
}
现在,我定义了一个 DocumentListener
来监视对 Document
的更改。这个 DocumentListener
需要一个 "slave" Document
,这个侦听器使用它来更新
public static class DocumentHandler implements DocumentListener {
private MirrorDocument slaveDocument;
private boolean ignoreUpdates = false;
public DocumentHandler(MirrorDocument slaveDocument) {
this.slaveDocument = slaveDocument;
}
@Override
public void insertUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
String text = e.getDocument().getText(e.getOffset(), e.getLength());
slaveDocument.setIgnoreUpdates(true);
slaveDocument.insertString(e.getOffset(), text, null);
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
slaveDocument.setIgnoreUpdates(true);
slaveDocument.remove(e.getOffset(), e.getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
}
现在,真正复杂的部分是 ignoreUpdates
标志。基本上,这是在事件发生时所做的,首先我们检查触发事件的 Document
的 ignoreUpdates
标志,如果它是 false
,我们继续设置 ignoreUpdates
标记 slaveDocument
到 true
,这会阻止它 DocumentListener
处理任何新事件然后更新 slaveDocument
好吧,这可能看起来有点奇怪,我很抱歉,但相信我,这是有道理的……(总有一天……当它发生时,你可以向我解释)
因此,接下来,我们需要创建所有内容并将其粘合在一起...
JTextArea left = new JTextArea(10, 20);
JTextArea right = new JTextArea(10, 20);
MirrorDocument leftDoc = new MirrorDocument();
MirrorDocument rightDoc = new MirrorDocument();
left.setDocument(leftDoc);
right.setDocument(rightDoc);
leftDoc.addDocumentListener(new DocumentHandler(rightDoc));
rightDoc.addDocumentListener(new DocumentHandler(leftDoc));
所以我们创建了两个JTextArea
,left
和right
。我们创建两个 MirrorDocument
s,每个 JTextArea
一个,然后我们创建两个 DocumentHandler
s,每个 JTextArea
一个,并提供相反的 Document
作为 slave (left
为rightDoc
,right
为leftDoc
),这允许事件交叉并发生更新
这允许我们设置类似...
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.logging.Level;
import java.util.logging.Logger;
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.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
public class MirrorTextAreas {
public static void main(String[] args) {
new MirrorTextAreas();
}
public MirrorTextAreas() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JTextArea left = new JTextArea(10, 20);
JTextArea right = new JTextArea(10, 20);
setLayout(new GridLayout(1, 2));
add(new JScrollPane(left));
add(new JScrollPane(right));
MirrorDocument leftDoc = new MirrorDocument();
MirrorDocument rightDoc = new MirrorDocument();
left.setDocument(leftDoc);
right.setDocument(rightDoc);
leftDoc.addDocumentListener(new DocumentHandler(rightDoc));
rightDoc.addDocumentListener(new DocumentHandler(leftDoc));
}
}
public class MirrorDocument extends PlainDocument {
private boolean ignoreUpdates;
public void setIgnoreUpdates(boolean ignoreUpdates) {
this.ignoreUpdates = ignoreUpdates;
}
public boolean isIgnoreUpdates() {
return ignoreUpdates;
}
}
public static class DocumentHandler implements DocumentListener {
private MirrorDocument slaveDocument;
private boolean ignoreUpdates = false;
public DocumentHandler(MirrorDocument slaveDocument) {
this.slaveDocument = slaveDocument;
}
@Override
public void insertUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
String text = e.getDocument().getText(e.getOffset(), e.getLength());
slaveDocument.setIgnoreUpdates(true);
slaveDocument.insertString(e.getOffset(), text, null);
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
slaveDocument.setIgnoreUpdates(true);
slaveDocument.remove(e.getOffset(), e.getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
}
}
好的,这大约是我们需要的一半,接下来我们需要能够过滤输入到其中一个字段中的内容,以便我们可以更改,这可以通过 Implementing a Document Filter
我正在尝试编写一个程序来显示两个 Jtextareas,这两个都是可编辑的。目标是当您编辑 textAreaRom(输入罗马数字)时,第二个区域 (textAreaArab) 将显示等效的阿拉伯数字。但问题是我无法让这件事实时发生。我已经阅读过有关使用 DocumentListeners 的信息,但是,这是我第一次进行 GUI 编程,我不确定我将如何实现它。什么都有帮助。我是 GUI 和 Whosebug 的新手,所以请多多关照!
注意:我的转换方法都很完美。
public class ArabicToRomanGUI_Hard extends JFrame
{
private static final long serialVersionUID = 1L;
private static String input = "";
private static String output = "";
//constructor to add text fields to frame
public ArabicToRomanGUI_Hard()
{
//JFrame frame = new JFrame("Convert Back And Forth");
final JTextField enterRomNumber = new JTextField(20);
final JTextArea textAreaRom = new JTextArea(20,20);
final JTextField enterArabNumber = new JTextField(20);
final JTextArea textAreaArab = new JTextArea(20,20);
setLayout(new FlowLayout());
enterRomNumber.setText("Please enter a Roman numeral");
enterArabNumber.setText("Please enter a Arabic Number");
textAreaRom.setEditable(true);
textAreaArab.setEditable(true);
//textAreaRom.setText(enterRomNumber.getText());
//textAreaArab.setText(enterArabNumber.getText());
if(textAreaRom.isFocusOwner() == true)
{
textAreaRom.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
{
e.getKeyChar();
input += e.getKeyChar();
ConversionLogic_Hard.ConvertFromRomanToArabic(input); //convert
ConversionLogic_Hard.getCheckFail(); //check if conversion is valid.
output = ConversionLogic_Hard.getConvertedRomanNumeral(); //get the conversion
while(ConversionLogic_Hard.getCheckFail() == true && textAreaArab.isFocusOwner() == false)
{
textAreaArab.setText(output);
}
textAreaArab.setText(input);
}
}
});
}
getContentPane().add(enterRomNumber, BorderLayout.EAST);
getContentPane().add(textAreaRom, BorderLayout.WEST);
}
你其实有3个问题...
- 在更新第一个文本组件时更新第二个文本组件,这相对容易。
- 在更新第二个文本组件时更新第一个文本组件...好吧,这变得非常复杂非常快。
- 过滤输入的文本。 Implementing a Document Filter 这实际上相对容易
现在,真正的问题是#2,这是因为当第一个字段试图更新第二个字段时,您可能很快就会陷入一个令人讨厌的地方,这会触发和事件导致第二个字段更新触发第一个字段和导致第一个字段更新第二个字段的事件......你开始明白了。
幸运的是,Swing 实际上不会让它变得那么糟糕,并且会抛出 IllegalStateException
为了克服这个问题,你需要有某种方法来知道什么时候对 Document
的更新是由从属字段触发的,或者它是由其他东西触发的(比如 setText
被调用,用户在字段中键入或粘贴文本)并忽略其中一些事件
现在,可能有一种非常酷且简单的方法可以做到这一点,但我的大脑今天不在 "simple" 模式,抱歉。
所以,我从自定义 Document
开始,它基本上有一个允许我检查其状态的标志
public class MirrorDocument extends PlainDocument {
private boolean ignoreUpdates;
public void setIgnoreUpdates(boolean ignoreUpdates) {
this.ignoreUpdates = ignoreUpdates;
}
public boolean isIgnoreUpdates() {
return ignoreUpdates;
}
}
现在,我定义了一个 DocumentListener
来监视对 Document
的更改。这个 DocumentListener
需要一个 "slave" Document
,这个侦听器使用它来更新
public static class DocumentHandler implements DocumentListener {
private MirrorDocument slaveDocument;
private boolean ignoreUpdates = false;
public DocumentHandler(MirrorDocument slaveDocument) {
this.slaveDocument = slaveDocument;
}
@Override
public void insertUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
String text = e.getDocument().getText(e.getOffset(), e.getLength());
slaveDocument.setIgnoreUpdates(true);
slaveDocument.insertString(e.getOffset(), text, null);
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
slaveDocument.setIgnoreUpdates(true);
slaveDocument.remove(e.getOffset(), e.getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
}
现在,真正复杂的部分是 ignoreUpdates
标志。基本上,这是在事件发生时所做的,首先我们检查触发事件的 Document
的 ignoreUpdates
标志,如果它是 false
,我们继续设置 ignoreUpdates
标记 slaveDocument
到 true
,这会阻止它 DocumentListener
处理任何新事件然后更新 slaveDocument
好吧,这可能看起来有点奇怪,我很抱歉,但相信我,这是有道理的……(总有一天……当它发生时,你可以向我解释)
因此,接下来,我们需要创建所有内容并将其粘合在一起...
JTextArea left = new JTextArea(10, 20);
JTextArea right = new JTextArea(10, 20);
MirrorDocument leftDoc = new MirrorDocument();
MirrorDocument rightDoc = new MirrorDocument();
left.setDocument(leftDoc);
right.setDocument(rightDoc);
leftDoc.addDocumentListener(new DocumentHandler(rightDoc));
rightDoc.addDocumentListener(new DocumentHandler(leftDoc));
所以我们创建了两个JTextArea
,left
和right
。我们创建两个 MirrorDocument
s,每个 JTextArea
一个,然后我们创建两个 DocumentHandler
s,每个 JTextArea
一个,并提供相反的 Document
作为 slave (left
为rightDoc
,right
为leftDoc
),这允许事件交叉并发生更新
这允许我们设置类似...
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.logging.Level;
import java.util.logging.Logger;
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.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
public class MirrorTextAreas {
public static void main(String[] args) {
new MirrorTextAreas();
}
public MirrorTextAreas() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JTextArea left = new JTextArea(10, 20);
JTextArea right = new JTextArea(10, 20);
setLayout(new GridLayout(1, 2));
add(new JScrollPane(left));
add(new JScrollPane(right));
MirrorDocument leftDoc = new MirrorDocument();
MirrorDocument rightDoc = new MirrorDocument();
left.setDocument(leftDoc);
right.setDocument(rightDoc);
leftDoc.addDocumentListener(new DocumentHandler(rightDoc));
rightDoc.addDocumentListener(new DocumentHandler(leftDoc));
}
}
public class MirrorDocument extends PlainDocument {
private boolean ignoreUpdates;
public void setIgnoreUpdates(boolean ignoreUpdates) {
this.ignoreUpdates = ignoreUpdates;
}
public boolean isIgnoreUpdates() {
return ignoreUpdates;
}
}
public static class DocumentHandler implements DocumentListener {
private MirrorDocument slaveDocument;
private boolean ignoreUpdates = false;
public DocumentHandler(MirrorDocument slaveDocument) {
this.slaveDocument = slaveDocument;
}
@Override
public void insertUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
String text = e.getDocument().getText(e.getOffset(), e.getLength());
slaveDocument.setIgnoreUpdates(true);
slaveDocument.insertString(e.getOffset(), text, null);
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
Document doc = e.getDocument();
if (doc instanceof MirrorDocument) {
MirrorDocument md = (MirrorDocument) doc;
if (!md.isIgnoreUpdates()) {
try {
slaveDocument.setIgnoreUpdates(true);
slaveDocument.remove(e.getOffset(), e.getLength());
} catch (BadLocationException ex) {
ex.printStackTrace();
} finally {
slaveDocument.setIgnoreUpdates(false);
}
}
}
}
@Override
public void changedUpdate(DocumentEvent e) {
}
}
}
好的,这大约是我们需要的一半,接下来我们需要能够过滤输入到其中一个字段中的内容,以便我们可以更改,这可以通过 Implementing a Document Filter