从另一个JtextArea实时更新一个JtextArea [英] Live updating one JtextArea from another JtextArea

查看:101
本文介绍了从另一个JtextArea实时更新一个JtextArea的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个程序,该程序将显示两个Jtextareas,这两个都是可编辑的.目的是当您编辑textAreaRom(输入罗马数字)时,第二个区域(textAreaArab)将显示等效的阿拉伯数字.但问题是我无法实时做到这一点.我已经阅读过有关使用DocumentListeners的信息,但这是我第一次进行GUI编程,并且我不确定如何实现它.任何帮助.我是GUI和StackOverflow的新手,所以很好!

注意:我的转换方法都可以正常工作.

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

解决方案

您实际上遇到了三个问题...

  1. 在更新第一个文本组件时更新第二个文本组件,这相对容易.
  2. 在第二个文本组件更新时更新第一个文本组件...嗯,这使REAL复杂的REAL很快了.
  3. 过滤输入的文本.通过实现文档过滤器,这实际上相对容易

现在,真正的问题是#2,这是因为当第一个字段尝试更新第二个字段时,您可能很快就进入了一个讨厌的地方,这触发并触发了导致第二个字段更新第一个字段的事件触发事件并导致第一个字段更新第二个字段...,您开始了解这个想法.

幸运的是,Swing实际上不会让它变坏,并且会抛出IllegalStateException

要解决这个问题,您需要某种方式来知道何时从属字段触发对Document的更新,或者何时由其他字段触发对它的触发(例如,调用setText时,用户在字段中输入或粘贴文本),而忽略其中一些事件

现在,可能有一种非常酷而简单的方法来完成此操作,但是对不起,我的大脑今天还没有处于简单"模式.

所以,我从一个自定义的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带有一个从属" 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标志周围.基本上,这是在事件发生时执行的操作,首先我们检查触发事件的DocumentignoreUpdates标志,如果它是false,则继续将slaveDocumentignoreUpdates标志设置为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));

因此,我们创建了两个JTextArealeftright.我们创建两个MirrorDocument,每个JTextArea一个,然后创建两个DocumentHandler,每个JTextArea一个,并提供相反的Document作为从属(对于leftleftDoc表示right),这样就可以进行事件交叉和更新

这使我们可以设置类似...

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

    }

}

好的,这大约是我们需要的一半,接下来我们需要能够过滤输入到其中一个字段中的内容,以便我们可以进行更改,这可以通过

You actually have three problems...

  1. Updating a second text component when the first is updated, which is, relatively easy.
  2. Update the first text component when the second is updated...well, that got REAL complicated REAL fast.
  3. Filter the text as it's been entered. This is actually relatively easy by Implementing a Document Filter

Now, the real problem is #2, this is because you could end up in a nasty place real fast as the first field tries to update the second field, which triggers and event which causes the second field to update the first field which triggers and event which causes the first field to update the second field ... and you start to get the idea.

Fortunately, Swing actually won't let it get that bad, and will throw a IllegalStateException

To over come this, you need to have some kind of way to know when an update to a Document is been triggered by the slave field or when it's been triggered by something else (like setText been called, the user typing or pasting text into the field) and ignore some of those events

Now, there's probably a really cool and simply way to do this, but my brain is not in "simple" mode today, sorry.

So, I start with a custom Document, this basically has a flag which allows me to inspect its state

public class MirrorDocument extends PlainDocument {

    private boolean ignoreUpdates;

    public void setIgnoreUpdates(boolean ignoreUpdates) {
        this.ignoreUpdates = ignoreUpdates;
    }

    public boolean isIgnoreUpdates() {
        return ignoreUpdates;
    }

}

Now, I define a DocumentListener to monitor changes to a Document. This DocumentListener takes a "slave" Document which is used by this listener to update

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

}

Now, the really tripy part here is around the ignoreUpdates flag. Basically, what this does is when a event occurs, first we check the ignoreUpdates flag of the Document which triggered the event, if it's false, we proceeded to set the ignoreUpdates flag of the slaveDocument to true, which prevents it's DocumentListener from processing any new events and then update the slaveDocument

Okay, this might seem a bit weird, and I'm sorry, but trust me, this will make sense...(one day ... and when it does, you can explain it back to me)

So, next, we need to create everything and glue it altogether...

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

So we create two JTextAreas, left and right. We create two MirrorDocuments, one for each JTextArea, we then create two DocumentHandlers, one for each JTextArea and provide the opposite Document as the slave (rightDoc for left and leftDoc for right), this allows for the event cross over and updating to occur

This allows us to set up something like...

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

    }

}

Okay, so that's about half of what we need, next we need to be able to filter the content been entered into one of the fields so we can change, this can be accomplished by Implementing a Document Filter

这篇关于从另一个JtextArea实时更新一个JtextArea的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆