JTextField take twice the input, but why? - java

I wanna make a programmable calculator, i got the basic GUI, and now i'm trying to set up the buttons, and the display. My display text will be "0" basically and if the user type in a number, that number should to be displayed. I tried to do it with KeyListener, but if i press a key it will display the key twice. Why?
textField.addKeyListener(new KeyListener(){
boolean newNumber = true;
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == e.VK_BACK_SPACE && textField.getText().length() == 1){
textField.setText("0");
newNumber = true;
}
if(textField.getText().equals("0") && newNumber){
textField.setText(KeyEvent.getKeyText(keyCode));
newNumber = false;
}
}
public void keyReleased(KeyEvent e) {
}
});
Before input:
After "1" input:

Here a simple solution:
If you use keyPressed, you have to do something in keyReleased and this become
complicated. keyTyped is a more simple way.
You can use e.consume() to prevent having the double digit inserted.
textField.addKeyListener(new KeyListener() {
int codeDelete = KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_DELETE);
int codeBackSpace = KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_BACK_SPACE);
#Override
public void keyTyped(KeyEvent e) {
char keyChar = e.getKeyChar();
if (textField.getText().length() == 0) {
textField.setText("0");
}
else if (textField.getText().equals("0") && keyChar != codeDelete && keyChar != codeBackSpace) {
textField.setText(String.valueOf(e.getKeyChar()));
e.consume();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});

For doing that, I derive PlainDocument like this:
import java.awt.EventQueue;
import java.util.regex.Pattern;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class DigitDocument extends PlainDocument {
private static final long serialVersionUID = 1L;
protected static final Pattern patternStartZero = Pattern.compile("^0.+");
protected final JTextField textField;
private final int limit;
private final Runnable runnableFormat;
public DigitDocument(JTextField textField, int limit) {
super();
this.textField = textField;
this.limit = limit;
runnableFormat = new Runnable() {
#Override
public void run() {
String text = textField.getText();
if (text.length() == 0) {
textField.setText("0");
}
else if (patternStartZero.matcher(text).matches()) {
textField.setText(text.replaceAll("^0+", ""));
}
}
};
}
#Override
public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
str = str.replaceAll("[^0-9]", "");
if (str.length() == 0)
return;
else if ((getLength() + str.length()) <= limit)
super.insertString(offset, str, attr);
EventQueue.invokeLater(runnableFormat);
}
#Override
public void remove(int offs, int len) throws BadLocationException {
if (!"0".equals(textField.getText()))
super.remove(offs, len);
EventQueue.invokeLater(runnableFormat);
}
}
The usage is:
textField.setDocument(new DigitDocument(textField, 10));
textField.setText("0");
In DigitDocument,
First arg is the JTextField himself.
Second arg (10) is the maximum input length,
You can enter only digit.

Related

Problems with redirecting console input in java

I am having trouble redirecting input from the console to a GUI in Java.
I have received an assignment, to build a Java command based game. That game includes i.e. the Parser and Console classes. The Parser is used to recognize commands, and Console is a graphical representation of a console.
The Parser class are using System.in and Scanner() to read the commands.
The Console class are redirecting the input from a jTextArea object by using System.setIn().
The Parser works fine with Intellij console and Windows cmd, but the Parser does not receive the text line when I redirect the input. What am I doing wrong?
The code in a test version.
Just run the Console class to open the console window. In the window type a word and press Enter. If it works, you will see your word repeated twice in the window below your word. If it doesn't work, your word will only be repeated once below your word.
Console:
import javax.swing.*;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.Highlighter.HighlightPainter;
import java.awt.*;
import java.awt.event.*;
import java.io.ByteArrayInputStream;
import java.util.Scanner;
public class Console implements KeyListener, ActionListener {
final String title = "World of Plastic";
final int width = 1380;
final int height = 750;
final String font = "Consolas";
final int fontSize = 12;
final int fontStyle = Font.PLAIN;
final JTextArea jta;
final HighlightPainter painter = new DefaultHighlightPainter(Color.gray);
int initialCaretPosition = 0;
// key codes
final int BACKSPACE = 8;
final int ENTER = 10;
final int PG_UP = 33;
final int PG_DN = 34;
final int END = 35;
final int HOME = 36;
final int LEFT_ARROW = 37;
final int UP_ARROW = 38;
final int RIGHT_ARROW = 39;
final int DOWN_ARROW = 40;
final int A = 65;
final int H = 72;
public Console() {
JFrame jf = this.frame();
//*** JTextArea ***//
this.jta = this.textArea("", 1, 1, false);
this.jta.addKeyListener(this);
// remove all mouse listeners
for (MouseListener listener : this.jta.getMouseListeners()) {
this.jta.removeMouseListener(listener);
}
// remove all mouse motion listeners
for (MouseMotionListener listener : this.jta.getMouseMotionListeners()) {
this.jta.removeMouseMotionListener(listener);
}
// remove all mouse wheel listeners
for (MouseWheelListener listener : this.jta.getMouseWheelListeners()) {
this.jta.removeMouseWheelListener(listener);
}
//*** Scrollable JTextArea ***//
jf.add(this.scrolls(15, 15, this.width - 45, this.height - 70));
jf.setVisible(true);
System.setOut(new Interceptor(System.out, this));
}
public static void main(String[] args) {
Console cfjp = new Console();
//new Game().play();
// A simpel parser
while (true) {
System.out.println();
System.out.print("> ");
Scanner reader = new Scanner(System.in);
System.out.println("parser " + reader.nextLine());
}
}
public void actionPerformed(ActionEvent ae) {
System.out.println("actionPerformed");
}
public void keyTyped(KeyEvent ke) {
}
public void keyReleased(KeyEvent ke) {
}
public void keyPressed(KeyEvent ke) {
int keyCode = ke.getKeyCode();
if (keyCode == PG_UP || keyCode == PG_DN || keyCode == UP_ARROW || keyCode == DOWN_ARROW) {
ke.consume();
} else if (keyCode == A && ke.getModifiersEx() == InputEvent.CTRL_DOWN_MASK) {
//this.highlightText(this.getStartCaretPosition(), this.getEndCaretPosition());
ke.consume();
} else if (keyCode == HOME) {
this.setCaretPosition(this.getStartCaretPosition());
ke.consume();
} else if (keyCode == END) {
this.setCaretPosition(this.getEndCaretPosition());
ke.consume();
} else if (keyCode == RIGHT_ARROW || keyCode == LEFT_ARROW || keyCode == BACKSPACE ||
(keyCode == H && ke.getModifiersEx() == InputEvent.CTRL_DOWN_MASK)) {
int pos = this.getCaretPosition();
if (pos <= this.getStartCaretPosition() || pos >= this.getEndCaretPosition()) {
ke.consume();
}
} else if (keyCode == ENTER) {
int from = this.getStartCaretPosition();
int to = this.getEndCaretPosition();
this.setStartCaretPosition(to);
try {
String inputFromUser = this.jta.getText(from, to - from);
System.out.println("\ninputFromUser " + inputFromUser.trim());
ByteArrayInputStream bais = new ByteArrayInputStream((inputFromUser).getBytes());
System.setIn(bais);
//System.setIn(new ByteArrayInputStream("5".getBytes()));
//System.setIn(new ByteArrayInputStream(inputFromUser.getBytes(StandardCharsets.UTF_8)));
} catch (Exception ignored) {
}
} else if (this.getCaretPosition() < this.getStartCaretPosition()) {
this.setCaretPosition(this.getEndCaretPosition());
}
}
public int getCaretPosition() {
return this.jta.getCaretPosition();
}
public void setCaretPosition(int position) {
this.jta.setCaretPosition(position);
}
public int getStartCaretPosition() {
return this.initialCaretPosition;
}
public void setStartCaretPosition(int position) {
this.setCaretPosition(position);
this.initialCaretPosition = position;
}
public int getEndCaretPosition() {
return this.jta.getDocument().getLength();
}
public void print(String text) {
this.jta.append(text);
this.setStartCaretPosition(this.getEndCaretPosition());
}
public JFrame frame() {
JFrame tmpJF = new JFrame(this.title);
tmpJF.setSize(this.width, this.height);
tmpJF.setLocationRelativeTo(null);
tmpJF.setLayout(null);
tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tmpJF.setResizable(false);
return tmpJF;
}
public JTextArea textArea(String text, int rows, int columns, boolean lineWrap) {
JTextArea tmpJTA = new JTextArea(text, rows, columns);
tmpJTA.setEditable(true);
tmpJTA.setLineWrap(lineWrap);
tmpJTA.setWrapStyleWord(true);
tmpJTA.setFont(new Font(this.font, this.fontStyle, this.fontSize));
tmpJTA.setForeground(Color.WHITE);
tmpJTA.setBackground(Color.black);
return tmpJTA;
}
public JScrollPane scrolls(int xpos, int ypos, int width, int height) {
JScrollPane tmpJSP = new JScrollPane(this.jta);
tmpJSP.setBounds(xpos, ypos, width, height);
tmpJSP.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
tmpJSP.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
return tmpJSP;
}
}
Interceptor:
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
public class Interceptor extends PrintStream {
private final Console obj;
public Interceptor(OutputStream out, Console obj) {
super(out, true);
this.obj = obj;
}
#Override
public void print(boolean b) {
this.obj.print(String.valueOf(b));
}
#Override
public void print(char c) {
this.obj.print(String.valueOf(c));
}
#Override
public void print(char[] s) {
this.obj.print(Arrays.toString(s));
}
#Override
public void print(double d) {
this.obj.print(String.valueOf(d));
}
#Override
public void print(float f) {
this.obj.print(String.valueOf(f));
}
#Override
public void print(int i) {
this.obj.print(String.valueOf(i));
}
#Override
public void print(long l) {
this.obj.print(String.valueOf(l));
}
#Override
public void print(Object obj) {
if (obj != null) {
this.obj.print(obj.toString());
}
this.obj.print("null");
}
#Override
public void print(String s) {
this.obj.print(String.valueOf(s));
}
#Override
public void println() {
this.obj.print("\n");
}
#Override
public void println(boolean x) {
this.obj.print(x + "\n");
}
#Override
public void println(char x) {
this.obj.print(x + "\n");
}
#Override
public void println(char[] x) {
this.obj.print(Arrays.toString(x) + "\n");
}
#Override
public void println(double x) {
this.obj.print(x + "\n");
}
#Override
public void println(float x) {
this.obj.print(x + "\n");
}
#Override
public void println(int x) {
this.obj.print(x + "\n");
}
#Override
public void println(long x) {
this.obj.print(x + "\n");
}
#Override
public void println(Object x) {
if (x != null) {
this.obj.print(x.toString() + "\n");
}
this.obj.print("null\n");
}
#Override
public void println(String x) {
this.obj.print(x + "\n");
}
}
The problem is that with
ByteArrayInputStream bais = new ByteArrayInputStream((inputFromUser).getBytes());
System.setIn(bais);
you replace the System.in InputStream, but your code in main
Scanner reader = new Scanner(System.in);
System.out.println("parser " + reader.nextLine());
is still waiting on the old System.in and therefore never receives any characters.
One way to solve it is to create a connected pair of PipedInputStream / PipedOutputStream and use these:
static PipedOutpuStream out;
public static void main(String[] args) {
PipedInputStream in = new PipedInputStream();
out = new PipedOutputStream();
in.connect(out);
System.setIn(in);
// rest of your main
}
public void keyPressed(KeyEvent ke) {
// much code left out
try {
String inputFromUser = this.jta.getText(from, to - from);
System.out.println("\ninputFromUser " + inputFromUser.trim());
out.write((inputFromUser + "\n").getBytes());
out.flush();
} catch (Exception ignored) {
}
// much code left out
}
I made PipedOutputStream out into a static field because of laziness, you could also pass it as constructor argument into the Console constructor.

documentlistener with invokelater goes infinite loop

I have a Jpanel with textfield. I am using documentListener to save the changes as the user types in the text field. User can type between 1-1000, if he types anything else, there would be a error message pop-up.
Now, I am using invokeLater, but that causes the infinite loop, if the user enters >1000. How can I fix this.
mMaxLabelLength = new JTextField();
mMaxLabelLength.getDocument().addDocumentListener(this);
#Override
public void changedUpdate(DocumentEvent arg0)
{
}
#Override
public void insertUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
#Override
public void removeUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
private boolean saveActions()
{
// get text
String strValue = mMaxLabelLength.getText();
// validate: must be positive integer between 1-1000;
boolean bSaveIt = true;
try
{
int nValue = Integer.parseInt(strValue);
if (nValue < 1 || nValue > 1000)
bSaveIt = false;
}
catch (NumberFormatException ne)
{
bSaveIt = false;
}
// save data to properties if valid
if (bSaveIt)
{
//do something
}
else
{
// error message
JOptionPane.showMessageDialog(this, "Please enter an integer value between 1 and 1000.", "Invalid Entry", JOptionPane.INFORMATION_MESSAGE);
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
int nMaxLabel = getMaxPieLabel();
mMaxLabelLength.setText(new Integer(nMaxLabel).toString());
}
});
return false;
}
setVisible(true);
return true;
}
It's not really the domain of responsibility for the DocumentListener to modify the state of the Document or to interact with the UI.
Instead, you should probably be using a DocumentFilter, which will allow you to catch the invalid state before its commit to the Document and a custom event notification to alert interested parties that a violation has occurred, for example...
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(20, 20, 20, 20));
JTextField field = new JTextField(10);
LimitedRangeDocumentFilter filter = new LimitedRangeDocumentFilter(1, 1000);
filter.setLimitedRangeDocumentFilterListener(new LimitedRangeDocumentFilterListener() {
#Override
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text) {
JOptionPane.showMessageDialog(TestPane.this,
text + " is not within " + filter.getMin() + "-" + filter.getMax() + " range",
"Error",
JOptionPane.ERROR_MESSAGE);
}
});
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);
add(field);
}
}
public interface LimitedRangeDocumentFilterListener {
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text);
}
public class LimitedRangeDocumentFilter extends DocumentFilter {
private int min;
private int max;
private LimitedRangeDocumentFilterListener listener;
public LimitedRangeDocumentFilter(int min, int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
public void setLimitedRangeDocumentFilterListener(LimitedRangeDocumentFilterListener listener) {
this.listener = listener;
}
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String string, AttributeSet attr)
throws BadLocationException {
StringBuilder sb = new StringBuilder(string);
for (int i = sb.length() - 1; i >= 0; i--) {
char ch = sb.charAt(i);
if (!Character.isDigit(ch)) {
sb.deleteCharAt(i);
}
}
StringBuilder master = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
master.insert(offset, sb.toString());
if (wouldBeValid(master.toString())) {
super.insertString(fb, offset, sb.toString(), attr);
} else if (listener != null) {
listener.updateWouldBeInvalid(this, master.toString());
}
}
#Override
public void replace(DocumentFilter.FilterBypass fb,
int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
protected boolean wouldBeValid(String text) {
boolean wouldBeValid = false;
try {
int value = Integer.parseInt(text);
if (value >= min && value <= max) {
wouldBeValid = true;
}
} catch (NumberFormatException exp) {
}
return wouldBeValid;
}
}
}
See Implementing a Document Filter and DocumentFilter Examples for more details

Using an if statement to test if JTextField is an integer

I want my program to be able to tell if what is inside my two JTextFields is an integer or a String.
CODE
public void actionPerformed(ActionEvent e){
if(inputH.getText().equals(" Set Height ") ||
inputW.getText().equals(" Set Width ")){
JOptionPane.showMessageDialog(frame,
"Change Height And Width To A Number.",
"Change Height To A Number",
JOptionPane.ERROR_MESSAGE);
}
}
});
This if statement tests if what is in the JTextField is " Set Height " or " Set Width " but i want them to test if what is in them is a number, how would I do that?
i cant figure out the Integer.ParseInt. Please help.
Not sure exactly where in your code the test is being performed, but you can use this method to determine if a String is an integer:
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
}
// if exception isn't thrown, then it is an integer
return true;
}
Less expensive none exception based way, assuming your code does not need to throw an exception:
public static boolean isInt(String s){
for(int i = 0; i < s.length(); i++){
if(!Character.isDigit(s.charAt(i))){
return false;
}
}
return true;
}
For restricting a User from entering anything but digits, you can set a DocumentFilter on the JTextField.
Here is a small example :
import java.awt.*;
import javax.swing.*;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;
public class InputInteger
{
private JTextField tField;
private MyDocumentFilter documentFilter;
private void displayGUI()
{
JFrame frame = new JFrame("Input Integer Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
tField = new JTextField(10);
((AbstractDocument)tField.getDocument()).setDocumentFilter(
new MyDocumentFilter());
contentPane.add(tField);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
Runnable runnable = new Runnable()
{
#Override
public void run()
{
new InputInteger().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class MyDocumentFilter extends DocumentFilter
{
#Override
public void insertString(DocumentFilter.FilterBypass fp
, int offset, String string, AttributeSet aset)
throws BadLocationException
{
int len = string.length();
boolean isValidInteger = true;
for (int i = 0; i < len; i++)
{
if (!Character.isDigit(string.charAt(i)))
{
isValidInteger = false;
break;
}
}
if (isValidInteger)
super.insertString(fp, offset, string, aset);
else
Toolkit.getDefaultToolkit().beep();
}
#Override
public void replace(DocumentFilter.FilterBypass fp, int offset
, int length, String string, AttributeSet aset)
throws BadLocationException
{
int len = string.length();
boolean isValidInteger = true;
for (int i = 0; i < len; i++)
{
if (!Character.isDigit(string.charAt(i)))
{
isValidInteger = false;
break;
}
}
if (isValidInteger)
super.replace(fp, offset, length, string, aset);
else
Toolkit.getDefaultToolkit().beep();
}
}
Or one can simply use this approach, as given by #Carlos Heuberger
#Override
public void insertString(FilterBypass fb, int off
, String str, AttributeSet attr)
throws BadLocationException
{
// remove non-digits
fb.insertString(off, str.replaceAll("\\D++", ""), attr);
}
#Override
public void replace(FilterBypass fb, int off
, int len, String str, AttributeSet attr)
throws BadLocationException
{
// remove non-digits
fb.replace(off, len, str.replaceAll("\\D++", ""), attr);
}
You can process the key event in the action method also. Try this
First make a JTextField
JTextField j=new JTextField();
Then add KeyListner to this JTextField as
j.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
if(arg0.getKeyCode()>57 || arg0.getKeyCode()<48) {
//your error message and other handling code here
JOptionPane.showMessageDialog(PatentFrame, "Only integer allowed", "Message title",JOptionPane.ERROR_MESSAGE);
}
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
48 is ASCII code for 0 and 57 is ASCII code for 9. You can also ignore virtual keys like shift. See ASCII chart

Get a key from JTextArea

All I want to do, If I'm pressing '{' this key in JtextArea.automatically '}' this will be print also.
if(evt.KEY_PRESSED == '{')
System.out.print("}");
is this is okay??
for listening changes into JTextComponent is there DocumentListener, if you have to need control over inputed Char, sings, whitespace chars or word(s) you have to implements DocumentFilter
notice for Chars reservated by programing language(s) you have to use double escapes,
\\( instead of (
or
\\{ instead of {
otherwise you get
Exception in thread "AWT-EventQueue-0" java.util.regex.PatternSyntaxException:
Illegal repetition
for example
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class TextAreaTest extends JFrame {
private static final long serialVersionUID = 1L;
private JTextArea textArea;
public TextAreaTest() {
textArea = new JTextArea();
textArea.setPreferredSize(new Dimension(60, 32));
textArea.setOpaque(true);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
((AbstractDocument) textArea.getDocument()).setDocumentFilter(new DocumentFilter() {
#Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
string = string.replaceAll("\\{", "\\{}");
super.insertString(fb, offset, string, attr);
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
text = text.replaceAll("\\{", "\\{}");
//TODO must do something here
super.replace(fb, offset, length, text, attrs);
}
});
textArea.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
update(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
update(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
update(e);
}
private void update(DocumentEvent e) {
List<String> lines = getLines(textArea);
String lastLine = lines.get(lines.size() - 1);
int tabbedTextWidth = Utilities.getTabbedTextWidth(new Segment(
lastLine.toCharArray(), 0, lastLine.length()), textArea.getFontMetrics(textArea.getFont()), 0, null, 0);
int lineHeight = getLineHeight(textArea);
if (lines.size() * lineHeight > textArea.getHeight() || tabbedTextWidth > textArea.getWidth()) {
System.out.println("Too big! Should refuse the update!");
}
}
});
getContentPane().add(textArea);
}
private static List<String> getLines(JTextArea textArea) {
int lineHeight = getLineHeight(textArea);
List<String> list = new ArrayList<String>();
for (int num = 0;; num++) {
int i = textArea.viewToModel(new Point(0, num * lineHeight));
int j = textArea.viewToModel(new Point(0, (num + 1) * lineHeight));
if (i == 0 && j == 0) {
continue;
}
if (textArea.getDocument().getLength() == i && i == j) {
break;
}
String s = removeTrailingNewLine(textArea.getText().substring(i, j));
list.add(s);
//System.out.println(i + " " + j + " = " + s);
}
return list;
}
private static int getLineHeight(JTextArea textArea) {
return textArea.getFontMetrics(textArea.getFont()).getHeight();
}
private static String removeTrailingNewLine(String s) {
if (s.endsWith("\n")) {
return s.substring(0, s.length() - 1);
} else {
return s;
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TextAreaTest test = new TextAreaTest();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.pack();
test.setVisible(true);
}
});
}
}
You need KeyBinding
http://tips4java.wordpress.com/2008/10/10/key-bindings/
and
http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
I think this is what you are looking for
if(evt.getID() == evt.KEY_PRESSED) {
if(evt.getKeyChar() == '{') {
System.out.print("}");
}
}
Tested and works

How do I limit the amount of characters in JTextPane as the user types (Java)

I need to not allow any characters to be entered after X have been typed. I need to send a beep after X characters have been typed. I know how to do this after the user presses enter, but I need to do it before the user presses enter. The approach I found from Oracle's site is to add a DocumentSizeFilter to the JTextPane. I can't get this to notify the user when they have gone over (it doesn't work until they press enter). This is a sample of what I have.
public class EndCycleTextAreaRenderer extends JTextPane
implements TableCellRenderer {
private final int maxNumberOfCharacters = 200;
public EndCycleTextAreaRenderer() {
StyledDocument styledDoc = this.getStyledDocument();
AbstractDocument doc;
doc = (AbstractDocument)styledDoc;
doc.setDocumentFilter(new DocumentSizeFilter(maxNumberOfCharacters ));
}
Override the insertString method of the document in the JTextPane so that it doesn't insert any more characters once the maximum has been reached.
For example:
JTextPane textPane = new JTextPane(new DefaultStyledDocument() {
#Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
if ((getLength() + str.length()) <= maxNumberOfCharacters) {
super.insertString(offs, str, a);
}
else {
Toolkit.getDefaultToolkit().beep();
}
}
});
Update:
You can change your class as follows:
public class EndCycleTextAreaRenderer extends JTextPane implements TableCellRenderer {
private final int maxNumberOfCharacters = 200;
public EndCycleTextAreaRenderer() {
setStyledDocument(new DefaultStyledDocument() {
#Override
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
if ((getLength() + str.length()) <= maxNumberOfCharacters) {
super.insertString(offs, str, a);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
});
}
}
Here is a sample program, for you where, as you enter the fourth time into the TextPane it will beep, without even you pressing the Enter key:
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Toolkit;
public class TextPaneLimit extends JFrame
{
private JPanel panel;
private JTextPane tpane;
private AbstractDocument abDoc;
public TextPaneLimit()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
panel = new JPanel();
tpane = new JTextPane();
Document doc = tpane.getStyledDocument();
if (doc instanceof AbstractDocument)
{
abDoc = (AbstractDocument)doc;
abDoc.setDocumentFilter(new DocumentSizeFilter(3));
}
panel.add(tpane);
add(panel);
pack();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TextPaneLimit().setVisible(true);
}
});
}
}
class DocumentSizeFilter extends DocumentFilter {
private int max_Characters;
private boolean DEBUG;
public DocumentSizeFilter(int max_Chars) {
max_Characters = max_Chars;
DEBUG = false;
}
public void insertString(FilterBypass fb
, int offset
, String str
, AttributeSet a)
throws BadLocationException {
if (DEBUG) {
System.out.println("In DocumentSizeFilter's insertString method");
}
if ((fb.getDocument().getLength() + str.length()) <= max_Characters)
super.insertString(fb, offset, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
public void replace(FilterBypass fb
, int offset, int length
, String str, AttributeSet a)
throws BadLocationException {
if (DEBUG) {
System.out.println("In DocumentSizeFilter's replace method");
}
if ((fb.getDocument().getLength() + str.length()
- length) <= max_Characters)
super.replace(fb, offset, length, str, a);
else
Toolkit.getDefaultToolkit().beep();
}
}
Hope this might help.
I would suggest checking the # of characters with every key entered by adding a keyReleasedListener, it is something I used in a recent GUI of mine to check bounds seemingly instantly and display errors to the user as they typed.
Here is how I implemented it on one of my TextFields:
carbonTextField.addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(java.awt.event.KeyEvent evt)
{
carbonTextFieldKeyReleased(evt);
}
});
Check the following code:
txtpnDesc.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if(txtpnDesc.getText().length() == 30)
{
e.consume();
}
}
});

Categories