1

I have a JTextArea that I would want the user to input address of a person. I know that valid address that the user will enter will not exceed 5 rows and 10 columns. So I have set it to JTextArea (5,10). This way it works fine.

The problem is that when a user keeps on pressing enter more that 5 times, the text area will begin to resize. I do not want to put the text area in a JScrollPane since the text that the user will enter is not much for scrolling.

Question: How do we disable JTextArea from resizing when a user press enter?

Here is my code:

public class JTextAreaDemo {

private JFrame frame;

JTextAreaDemo(){
    frame= new JFrame();
    frame.setSize(300, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new net.miginfocom.swing.MigLayout());
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);

    JLabel label=new JLabel("Address :");
    JTextArea address= new JTextArea(5,20);
    frame.add(label,"cell 0 0");
    frame.add(address, "cell 1 0");
}

public static void main(String [] args){
    SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run() {
            new JTextAreaDemo();

        }});
    }
 }
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
CN1002
  • 1,115
  • 3
  • 20
  • 40

4 Answers4

2

You can try to use DocumentFilter, for example:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class TestFrame extends JFrame {

    public static void main(String... s) {
        new TestFrame();
    }

    private JTextArea area;

    public TestFrame() {
        init();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }


    private void init() {
        area = new JTextArea();
        ((AbstractDocument)area.getDocument()).setDocumentFilter(getFilter(5));
        add(new JScrollPane(area));
    }

    private DocumentFilter getFilter(final int lineCount) {
        return new DocumentFilter(){

            @Override
            public void replace(FilterBypass fb, int offset, int length,
                    String text, AttributeSet attrs)
                    throws BadLocationException {
                if(area.getLineCount()<=lineCount && area.getLineOfOffset(area.getCaretPosition())<lineCount)
                        if(text.contains("\n") && area.getLineCount()<lineCount)
                            super.replace(fb, offset, length, text, attrs);
                        else if(!text.contains("\n"))
                            super.replace(fb, offset, length, text, attrs);
            }
        };
    }

}
alex2410
  • 10,904
  • 3
  • 25
  • 41
  • Well, this is actually what I was looking for considering limiting the number of rows/lines.Thanks so much. – CN1002 Apr 23 '15 at 10:39
  • As a general rule of thumb, the filter shouldn't know about the text component, it kind of defeats the purpose. – MadProgrammer Apr 23 '15 at 11:58
  • @MadProgrammer Yes, but it just example. In that case we need method that count line numbers from `Document`. Also good catch about line wrapping. – alex2410 Apr 23 '15 at 12:08
2

As already stated, DocumentFilter can be used. I post this answer due to the elegant solution it offers.

public class JTextAreaDemo {

    private JFrame frame = new JFrame();
    JTextArea address = new JTextArea(5, 20);

    JTextAreaDemo() {

        JLabel label = new JLabel("Address :");
        frame.getContentPane().add(label, BorderLayout.CENTER);
        frame.getContentPane().add(address, BorderLayout.SOUTH);

        ((PlainDocument) address.getDocument()).setDocumentFilter(new LineFilter());

        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class LineFilter extends DocumentFilter {

        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {

            if (address.getLineCount() < 5 || !string.contains("\n"))
                super.insertString(fb, offset, string, attr);
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

            if (address.getLineCount() < 5 || !text.contains("\n"))
                super.replace(fb, offset, length, text, attrs);
        }
    }

    public static void main(String[] args) {

        new JTextAreaDemo();
    }
}

Although for user input overriding the method insertString won't be relevant, it is usually a good idea to cover all bases. Otherwise, it can be removed.

Note that there is no need for a JScrollBar.

Edit:

To allow @MadProgrammer to sleep quietly at night, the line counting is done (in a less elegant way) directly from the document:

@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

    String content = fb.getDocument().getText(0, fb.getDocument().getLength());
    Matcher matcher = Pattern.compile("\n").matcher(content);
    int lines = 0;
    while (matcher.find()) {
        lines++;
    }
    if (lines < 4 || !text.contains("\n"))
        super.replace(fb, offset, length, text, attrs);
}

The insertString method can use the same code.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • General rule of thumb, the filter shouldn't know about the UI/text component that's using it. Assuming that the text area doesn't have line wrapping enabled, then it becomes a relatively easy affair...if not... – MadProgrammer Apr 23 '15 at 11:57
  • @MadProgrammer I completely agree with the rule of thumb, although when the content (document side) affects the visuals (UI component side), I think there is merit for this. I added a rule-of-thumb-friendly solution. – user1803551 Apr 23 '15 at 12:27
  • In case of line wrap it doesn't help you. Examine [that](http://stackoverflow.com/questions/12837605/how-to-take-line-wrap-in-account-for-jtextarea-line-counting) – alex2410 Apr 23 '15 at 12:28
  • @alex2410 The OP demonstrated that they are not using line wrap. I would have accounted for it otherwise. – user1803551 Apr 23 '15 at 12:32
1

Use setPreferredSize(new Dimension(X,Y)) so that the JTextArea will keep the dimension you set, and wont move at all ! You'll still need to put your JTextArea inside a JScrollPane thought.

Mekap
  • 2,065
  • 14
  • 26
  • Well, setting the preferred size alongside using the `JScrollPane` worked. Setting the preferred size alone could not make it, anyway thanks for the tip. – CN1002 Apr 23 '15 at 10:04
  • @Giovanrich You're welcome, i edited my answer to your answer don't forget to close your question when you're done. – Mekap Apr 23 '15 at 10:05
  • JTextArea and MigLayout hates setPreferredSize, this is about line/word wrap for JTextArea inside JScrollPane, otherwise .... :-) – mKorbel Apr 23 '15 at 10:08
  • Well, I won't forget. How do I avoid it to move to sixth column? See @Blip second comment – CN1002 Apr 23 '15 at 10:09
  • I would avoid using something like this, as you don't control the many idiosyncrasies associated with fonts and font rendering – MadProgrammer Apr 23 '15 at 10:10
0

I would suggest that you should use an InputVerifier which will keep track of number of enters that have been entered in your JTextArea and when it reaches 4 then it should ignore the enters.

As you have pointed out in your comments DocumentListener would do the same and also KeyListener could do the same.

Blip
  • 3,061
  • 5
  • 22
  • 50
  • Doesn't `InputVerifer` only get notified on focus lost? This won't stop the user from overflowing the field with text when the field is set to wrapping, for example – MadProgrammer Apr 23 '15 at 10:12
  • @MadProgrammer How about `DocumentListener` ? - Doesn't it save the purpose of tracking? – CN1002 Apr 23 '15 at 10:14
  • @MadProgrammer I really overlooked that **Yes that is true** and I am correcting my answer to accommodate for that that. – Blip Apr 23 '15 at 10:14
  • `DocumentFilter` might be preferred, then you just reject input you don't want without causing a mutation error – MadProgrammer Apr 23 '15 at 10:20