Is there a way to make the end of a JTextArea editable and make anything that has already been printed to it not editable?
What I mean by this is if I've written "Hello World" for example to a JTextArea, how could I make it so that the user can type in whatever they want after "Hello World" but they cannot type before that or delete the already printed text?
Below is a small program to demonstrate my troubles...
public class Test {
public static void main(String[] args) {
//Here I create a simple JFrame with JTextArea
JTextArea textArea = new JTextArea();
JFrame frame = new JFrame();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setSize(250, 250);
textArea.setEditable(true);
textArea.setVisible(true);
frame.add(textArea);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*Here I print "Hello World" onto the text area.. after the ">>" I want the
the user to be able to type whatever they want.. however I don't want them
to be able to edit the "Hello World"*/
textArea.append("Hello World\n>>");
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
In the example the user is able to enter whatever text they want.. which is what I want.. however they are also able to edit the text that I printed using append.. which I don't want..
How can I solve this?
Yes, a DocumentFilter will work. Create one that only allows addition of text if the addition is at the end of the document -- that is if the offset equals the document's length. Also totally inactivate the remove method. Something like so:
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class MyFilter extends DocumentFilter {
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
throws BadLocationException {
// only insert text if at the end of the document
// if offset == document length
if (offset == fb.getDocument().getLength()) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
// only replace text if at the end of the document
// if offset == document length
if (offset == fb.getDocument().getLength()) {
super.replace(fb, offset, length, text, attrs);
}
}
@Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
// do nothing. Totally inactivate this
}
}
And you could test it like so:
import javax.swing.*;
import javax.swing.text.PlainDocument;
@SuppressWarnings("serial")
public class LimitedTextArea extends JPanel {
private JTextArea textArea = new JTextArea(15, 50);
public LimitedTextArea() {
// get textArea's Document and cast to PlainDocument:
PlainDocument document = (PlainDocument) textArea.getDocument();
// set the document's filter with "MyFilter"
document.setDocumentFilter(new MyFilter());
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane);
}
private static void createAndShowGui() {
LimitedTextArea mainPanel = new LimitedTextArea();
JFrame frame = new JFrame("LimitedTextArea");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}