views:

58

answers:

2

My objective here is to obtain a console-like-behaving component in Java, not necessarily in JTextArea, but this seemed like a logical thing to try first. Output is simple enough, using the methods provided by the JTextArea, but input is another thing. I want to intercept input, and act on it - character by character. I've found some examples on using a DocumentListener for something vaguely related, but it doesn't seem to allow me to easily check what was just typed in, which is what I need to decide how to act upon it.

Am I going about this correctly? Is there a better method for this?

I enclose the pertinent parts of my application code.

public class MyFrame extends JFrame {
    public MyFrame() {
        Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2));
        int x=(int)(frameSize.width/2);
        int y=(int)(frameSize.height/2);
        setBounds(x,y,frameSize.width,frameSize.height);


        console = new JTextArea("",25,80);
        console.setLineWrap(true);
        console.setFont(new Font("Monospaced",Font.PLAIN,15));
        console.setBackground(Color.BLACK);
        console.setForeground(Color.LIGHT_GRAY);
        console.getDocument().addDocumentListener(new MyDocumentListener());

        this.add(console);

    }

    JTextArea console;

}

class MyDocumentListener implements DocumentListener
{
    public void insertUpdate(DocumentEvent e)
    {
        textChanged("inserted into");
    }
    public void removeUpdate(DocumentEvent e)
    {
        textChanged("removed from");
    }
    public void changedUpdate(DocumentEvent e)
    {
        textChanged("changed");
    }
    public void textChanged(String action)
    {
        System.out.println(action);
    }
}

Thanks for any help.

EDIT1: I have attempted to do this using a JTextPane with a DocumentFilter, but when I input something, the method in the DocumentFilter isn't getting run. I enclose the modified code:

public class MyFrame extends JFrame {
    public MyFrame() {
        Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2));
        int x=(int)(frameSize.width/2);
        int y=(int)(frameSize.height/2);
        setBounds(x,y,frameSize.width,frameSize.height);

        console = new JTextPane();
        //console.setLineWrap(true);
        console.setFont(new Font("Monospaced",Font.PLAIN,15));
        console.setBackground(Color.BLACK);
        console.setForeground(Color.LIGHT_GRAY);
        StyledDocument styledDoc = console.getStyledDocument();
            if (styledDoc instanceof AbstractDocument) {
            doc = (AbstractDocument)styledDoc;
            doc.setDocumentFilter(new DocumentSizeFilter());
        }

        this.add(console);

    }

    JTextPane console;
    AbstractDocument doc;

}

class DocumentSizeFilter extends DocumentFilter {

        public DocumentSizeFilter() {

    }

    public void insertString(FilterBypass fb, int offs, String str, AttributeSet a) throws BadLocationException {
        System.out.println(str);
        if (str.equals("y")) {
            System.out.println("You have pressed y.");
        }
    }

    public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)  throws BadLocationException {

    }

}
A: 

I want to intercept input, and act on it

Then you should probably be using a DocumentFilter. See Implementing a Document Filter for more information.

camickr
I have attempted this, but for some reason, the results are unsatisfactory. I've edited the new approach into my post.
Abu Dhabi
@abu dhabi, did you copy the full example from the tutorial? I don't see your code for the replace() method. This is the method that is invoked when you edit a text component through the GUI. The insertString() method is invoked when you udpate the Document directly in your program using the Document.insertString() method.
camickr
I copied my code to the replace() method, but it doesn't get invoked from there either.
Abu Dhabi
Did you actually copy the code from the tutorial and test it?
camickr
A: 

There seems to be lots of different ways to customise Swing text components. When I did something similar to you I had success with a custom Document:

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class CustomDocument extends PlainDocument {
    @Override
    public void insertString(int offset, String string, AttributeSet attributeSet) throws BadLocationException {
        // Parse input - in this case convert everything to upper case
        string = string.toUpperCase();
        super.insertString(offset, string, attributeSet);
    }
}

Here is a main method to be able to test the code:

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(100, 100, 300, 300);
    frame.add(new JTextArea(new CustomDocument()));
    frame.setVisible(true);
}
Russ Hayward
This approach doesn't seem to work; I get an error underline at @Override, saying that I'm not overriding or replaying any method. I also get an error at the attributeSet variable, which seems to be invalid for this method - putting a null in the invocation of the super.insertString() method makes it compile, however. I also got a runtime exception that it was supposed to be a StyledDocument not PlainDocument, but resolved that by changing back to a JTextArea. Lastly, when I enter anything into the place after //parse input part, it does not get invoked.
Abu Dhabi
I have added the imports and a main method to demonstrate usage. If you need a StyledDocument then extend DefaultStyledDocument or HTMLDocument instead of PlainDocument.
Russ Hayward