Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit JTextArea max Rows and Columns?

I am using JTextArea in JScrollPane

I want to limit the maximum number of lines possible and the maximum chars in each line.

I need that the string will be exactly like on the screen, each line will end with '\n' (if there another line after it) and the user will be able to insert only X lines and Y chars in each line.

I tried to limit the lines but I don't know exactly how many lines do I have because of the line wrapping, The line wrapping is starting new line visually on the screen(because of the width of the JTextArea) but in the string of the component it is really the same line with no '\n' to indicate new line. I do not have an idea how to limit the max chars in each line while typing.

There are 2 stages:

  1. The typing of the string- keep that the user will not be able to type more then X lines and Y chars in each line. (even if the line wrap only visualy or the user typed '/n')
  2. Insert the string to the DB- after cliking 'OK' convert the string that every line will end with "/n" even if the user did not typed it and the line was wrapped only visualy.

There are few problems if i will count the chars in the line and insert '/n' in the end of the line, thats why i decided to do it in two stages. In the first stage ehile the user is typing i would rather only limit it visualy and force line wrpping or something similar. Only in the second stage when i save string i will add the '/n' even if the user did not typed it in the end of the lines!

Does anyone have an idea?


I know that i will have to use DocumentFilter OR StyledDocument.

Here is sample code that limit only the lines to 3:(but not the chars in row to 19)

private JTextArea textArea ;
textArea  = new JTextArea(3,19);
textArea  .setLineWrap(true);
textArea .setDocument(new LimitedStyledDocument(3));
JScrollPane scrollPane  = new JScrollPane(textArea

public class LimitedStyledDocument extends DefaultStyledDocument

    /** Field maxCharacters */
    int maxLines;

    public LimitedStyledDocument(int maxLines) {
        maxCharacters = maxLines;
    }

public void insertString(int offs, String str, AttributeSet attribute) throws BadLocationException {
    Element root = this.getDefaultRootElement();
    int lineCount = getLineCount(str);

    if (lineCount + root.getElementCount() <= maxLines){
        super.insertString(offs, str, attribute);
    }
    else {
        Toolkit.getDefaultToolkit().beep();
    }
}

 /**
 * get Line Count
 * 
 * @param str
 * @return the count of '\n' in the String
 */
private int getLineCount(String str){
    String tempStr = new String(str);
    int index;
    int lineCount = 0;

    while (tempStr.length() > 0){
        index = tempStr.indexOf("\n");
        if(index != -1){
        lineCount++;
            tempStr = tempStr.substring(index+1);
        }
    else{
        break;
        }
    }
    return lineCount;
   }
}
like image 968
Billbo bug Avatar asked Jan 26 '09 09:01

Billbo bug


People also ask

How do I stop JTextArea from expanding?

You can use JTextArea#setLineWrap(true) by default is set to false. Sets the line-wrapping policy of the text area. If set to true the lines will be wrapped if they are too long to fit within the allocated width. If set to false, the lines will always be unwrapped.

Is JTextArea editable?

The JTextArea class provides a component that displays multiple lines of text and optionally allows the user to edit the text.

How do I clear a JTextArea?

selectAll(); JTextArea0. replaceSelection(""); This selects the entire textArea and then replaces it will a null string, effectively clearing the JTextArea.

What is the default found for JTextArea?

Constructs a new TextArea. A default model is set, the initial string is null, and rows/columns are set to 0.


2 Answers

The following worked for me:

public class LimitedLinesDocument extends DefaultStyledDocument 
{    
  private static final String EOL = "\n";

  private int maxLines;

  public LimitedLinesDocument(int maxLines) 
  {    
    this.maxLines = maxLines;
  }

  public void insertString(int offs, String str, AttributeSet attribute) throws BadLocationException 
  {        
    if (!EOL.equals(str) || StringUtils.occurs(getText(0, getLength()), EOL) < maxLines - 1) 
    {    
      super.insertString(offs, str, attribute);
    }
  }
}

Where the StringUtils.occurs method is as follows:

public static int occurs(String str, String subStr) 
{    
  int occurrences = 0;
  int fromIndex = 0;

  while (fromIndex > -1) 
  {    
    fromIndex = str.indexOf(subStr, occurrences == 0 ? fromIndex : fromIndex + subStr.length());
    if (fromIndex > -1) 
    {    
      occurrences++;
    }
  }

  return occurrences;
}
like image 121
Nick Holt Avatar answered Oct 14 '22 05:10

Nick Holt


Here's my version, based on Nick Holt's version.

Just for the records, this will be used in a prototype and has not been tested much (if at all).

public class LimitedLinesDocument extends DefaultStyledDocument {
    private static final long serialVersionUID = 1L;

    private static final String EOL = "\n";

    private final int maxLines;
    private final int maxChars;

    public LimitedLinesDocument(int maxLines, int maxChars) {
        this.maxLines = maxLines;
        this.maxChars = maxChars;
    }

    @Override
    public void insertString(int offs, String str, AttributeSet attribute) throws BadLocationException {
        boolean ok = true;

        String currentText = getText(0, getLength());

        // check max lines
        if (str.contains(EOL)) {
            if (occurs(currentText, EOL) >= maxLines - 1) {
                ok = false;
            }
        } else {
            // check max chars
            String[] lines = currentText.split("\n");
            int lineBeginPos = 0;
            for (int lineNum = 0; lineNum < lines.length; lineNum++) {
                int lineLength = lines[lineNum].length();
                int lineEndPos = lineBeginPos + lineLength;

                System.out.println(lineBeginPos + "    " + lineEndPos + "    " + lineLength + "    " + offs);

                if (lineBeginPos <= offs && offs <= lineEndPos) {
                    System.out.println("Found line");
                    if (lineLength + 1 > maxChars) {
                        ok = false;
                        break;
                    }
                }
                lineBeginPos = lineEndPos;
                lineBeginPos++; // for \n
            }
        }

        if (ok)
            super.insertString(offs, str, attribute);
    }

    public int occurs(String str, String subStr) {
        int occurrences = 0;
        int fromIndex = 0;

        while (fromIndex > -1) {
            fromIndex = str.indexOf(subStr, occurrences == 0 ? fromIndex : fromIndex + subStr.length());
            if (fromIndex > -1) {
                occurrences++;
            }
        }

        return occurrences;
    }
}
like image 40
Frederic Morin Avatar answered Oct 14 '22 05:10

Frederic Morin