I'm using a JTextArea in a JFrame. I would like the tab key to insert four spaces instead of a tab.
The method setTabSize
does not work, as it puts a tab ('\t') in the contents of the text area.
How can I have JTextArea insert four spaces instead of a tab whenever I press the tab key? That way the getText() method will return indentations of four spaces for every tab.
CodePudding user response:
I would avoid using KeyListeners (as a general rule with JTextComponents) and even Key Bindings, since while Key Bindings would work for keyboard input, it wouldn't work for copy-and-paste.
In my mind, the best way is to use a DocumentFilter set on the JTextArea's Document (which is a PlainDocument, by the way). This way, even if you copy and paste text into the JTextAreas, one with tabs, then all the tabs will automatically be converted to 4 spaces on insertion.
For example:
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;
public class TestTextArea {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JTextArea textArea = new JTextArea(20, 50);
JScrollPane scrollPane = new JScrollPane(textArea);
int spaceCount = 4;
((PlainDocument) textArea.getDocument()).setDocumentFilter(new ChangeTabToSpacesFilter(spaceCount));
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
private static class ChangeTabToSpacesFilter extends DocumentFilter {
private int spaceCount;
private String spaces = "";
public ChangeTabToSpacesFilter(int spaceCount) {
this.spaceCount = spaceCount;
for (int i = 0; i < spaceCount; i ) {
spaces = " ";
}
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
throws BadLocationException {
string = string.replace("\t", spaces);
super.insertString(fb, offset, string, attr);
}
@Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
super.remove(fb, offset, length);
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
text = text.replace("\t", spaces);
super.replace(fb, offset, length, text, attrs);
}
}
}
So now, even if I copy and paste a document with tabs within it, into the JTextArea, all tabs will be automatically replaced with spaceCount
spaces.
CodePudding user response:
This is one of those “I wonder if…” moments.
Personally, I’d try a tackle the problem more directly, at the source. This means “trapping” the Tab event some how and “replacing” it’s functionality.