Restricting number of characters in a message in JTextPane - java

I have a JTextPane where I want to restrict the user to enter a message with only 200 characters. So, I have a KeyListener which listens for a Keyevent and checks for a KeyEvent. If the message is more than 200 characters, a JOptionPane.showMessageDialog is shown to display a warning to the user. This bit works fine.
The problem is that once the warning is displayed and the users clicks on 'OK' he can only use the Backspace key in the JTextPane. I want the user to be able to use the delete key, the arrow keys, the shift and control keys to be able to select the text to be deleted.
Can anybody suggest a way of achieving this??
// Add Key Listener to Send Field
chatEditorKeyListener = new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
checkKeystroke(e);
}
};
private void checkKeystroke(KeyEvent e)
{
//Check if enter or back space is entered
if( e.getKeyCode() != KeyEvent.VK_BACK_SPACE && e.getKeyCode() != KeyEvent.VK_ENTER )
{
// user is typing, so test the size as we go and report when we hit boundary
String text = messageBox.getText();
if(text.length() > maxMessageSize)
{
showAlertBox();
}
}
else if ( e.getKeyCode() == KeyEvent.VK_ENTER)
{
//User sending the message
e.consume();
String text = messageBox.getText();
if(text.length() > maxMessageSize)
{
showAlertBox();
}

Drag-and-drop. Copy-and-paste. Accessibility input methods. There are many reasons why this approach is not appropriate.
Instead restrict the contents through the Document. Set a DocumentFilter through AbstractDocument.setDocumentFilter so that you do not need to subclass or implement the document.
A pop up is not great for user experience. Be more subtle. Not allowing any more character will do (please don't beep!). Possibly add a countdown as twitter and stackoverflow do.

Read the section from the Swing tutorial on "Text Component Features" which contains a section on "Implementing a Document Filter" that does exactly what you want.

Test if the current size+1 hits the boundary, consume the event and show the message box.
It's important to comsume the event to never actually oversize your text box!

Related

EventListener Performed by case

I would like to know the best way to approach what I am trying to achieve, I can't figure out the logical path I should take.
I have a JTextField and a JTextButton, when input is added to the JTextField and either enter or the button is pressed, it will display on the JTextArea. Now, what I want is to choose when and what the JTextArea and Button do.
For example I want default Enter & Button to display next append text in my code. Then when a case is presented I want the JTextField to only accept either int or string and then once completed, I want it to go back to default.
I don't know if what I am trying to do is logical or best practice...
The idea behind this is, I have a story text based gui game. I want it to display text to the JTextArea and when Enter or button is pressed to display the next line of text and when in the story it requires user input, the JTextArea will look for that input.
So far I have an EventListener and ActionListener which submits what I type from JTextField to JTextArea, but that is about it.
Thanks for your assistance! I have solved my issue, not sure if this is the "Best Solution". I combined your solution with a bit of tweaking.
In this instance, buttonState is an int which can be changed throughout my code by calling a constructor "setButtonState". I could have made buttonState a static to make things easier, but thought I could keep things clean.
enterButton.addActionListener(new ActionListener()
{ //This is used so when the enter screen button is pressed, it will submit text from text field to text area.
public void actionPerformed(ActionEvent e) {
String text = inputTextField.getText();
InputTextFieldEvent event = new InputTextFieldEvent(this, text);
if (buttonState == 0) //Displays all text in JTextField to JTextArea, mostly for testing purposes.
{
if (textInputListener != null) {
textInputListener.setInputListenerOccurred(event);
}
}
if (buttonState == 1) //Only accepts string for answer
{
if (inputTextField.getText().matches("[a-zA-Z]+"))
{
textInputListener.setInputListenerOccurred(event);
}
else
{
getAppendMainTextArea("You have entered an invalid input, only letters are allowed.");
}
}
if (buttonState == 2) //Only accepts int for answer
{
if (inputTextField.getText().matches("[0-9]+"))
{
textInputListener.setInputListenerOccurred(event);
}
else
{
getAppendMainTextArea("You have entered an invalid input, only numbers are allowed.");
}
}
}
});

Swing- Add text between two textual points in JTextArea

Well, I decided to edit everything. So, the code goes like this:
public void actionPerformed(ActionEvent e) {
if (!uiCreator.getTextArea().getText().equalsIgnoreCase("Beggining text")) {
JOptionPane.showMessageDialog(null, "You must have main method first", "Error",
JOptionPane.ERROR_MESSAGE);
} else {
n = Integer.valueOf(JOptionPane.showInputDialog("..."));
l = Integer.valueOf(JOptionPane.showInputDialog("..."));
uiCreator.getTextArea()
.setText("Beggining text with few additions");
On the code above, I made it to check if JTextArea contains text that is needed and if it doesn't it will show an error message. If it does it will set a text with few more words.
Now. I also have more JButtons. So if one is clicked, it will also do the same thing. Check the text and if it meets all conditions, set new modified text. But, now, my problem comes here. I have this:
public void actionPerformed(ActionEvent e) {
if (!uiCreator.getTextArea().getText()
.equalsIgnoreCase("Beggining text with few additions")) {
JOptionPane.showMessageDialog(null, "Error, you don't have main or JFrame inside main", "Error",
JOptionPane.ERROR_MESSAGE);
} else {
uiCreator.getTextArea()
.setText("Beggining text with even more additions");
}
Which checks if JTextArea had "Beggining text with few additions" and if it did, change the text to Beggining text with even more additions. I have few more buttons that do the same thing. Now, I would like to know a way to let setText(some text) method be used regardless is there Beggining text with few additions or Beggining text with even more additions.
Don't use setText(...) to keep replacing all the text.
Instead you can use methods like:
replaceSelection(...);
getDocument().insertString(...);
to change part of the text or insert new text.

JTextField's real time formatting of user input

I would like to format the user input in real time, while they are typing.
For example, if I want the user to enter a date, I would like the text field to show in light gray the date format. The user would only be able to enter valid digits while he is typing.
If I need the user to enter a phone number, the format would be displayed in light gray in the text field and the user would only be able to enter valid digits...
A javascript example of this can be found here:
http://omarshammas.github.io/formancejs#dd_mm_yyyy
I looked at JFormattedTextField but it seems it doesn't prevent the user from typing wrong characters.
I am wondering how to do the same thing in Java as the javascript code linked above.
Any idea to help me get started or any lib already doing this?
Thanks in advance for any suggestion.
The KeyListener interface has three methods to be implemented: keyPressed, keyTyped and keyReleased. As each key is pressed you can do what you need to in this implemented listener. So for example, if the current key typed or the current contents of the text field is not to your approval, you can take the visual or logical action you need to take.
I don't like links generally, but here is a small tutorial on KeyListeners.
And here is an example to add a KeyListener to a JTextField:
usernameTextField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
JTextField textField = (JTextField) e.getSource();
String text = textField.getText();
textField.setText(text.toUpperCase());
}
public void keyTyped(KeyEvent e) {
// TODO: Do something for the keyTyped event
}
public void keyPressed(KeyEvent e) {
// TODO: Do something for the keyPressed event
}
});

JTextArea Transfer Focus

I'm trying to transfer focus from one JTextArea to another when the user hits tab.
Currently I'm using this code:
public void keyTyped(KeyEvent e) {
if(e.getKeyChar() == KeyEvent.VK_TAB){
enterTextArea.transferFocus();
}
}
This appears to work - the focus moves and you type in the next JTextArea - but actually the text stills gets appened to the first TextArea, meaning that performing a getText() on the second TextArea just returns "".
How do I make the text typed go to the second JTextArea rather than just get appended to the first?
EDIT: On further inspection this behavior was caused by a separate bug. No further help needed.
You can just transfer the text from 1 to 2 by using getText on the first one.
public void keyTyped(KeyEvent e) {
if(e.getKeyChar() == KeyEvent.VK_TAB){
enterTextArea.transferFocus();
String firstField = textField1.getText();
secondField.setText(firstField);
}
}
That way it will save from the first text area, and put it into the second one.
Hope this helps!

Java SWT: apply key events from List to Text field

I am making a component in SWT that contains a text field and a list. Whenever text is entered it filters the list. So far everything is working great and I am just trying to add some nice usability features.
What I want to do is listen for any key events in the List field, if it is Enter that is pressed I perform the 'ok' action (already done) but otherwise I want focus to change to the text field and have the key event triggered there. Basically, if the focus is on the List field and the user types something I want it to be automatically typed into the text field.
Responding to the keyPressed or keyReleased event is fine for setting the focus to the text field, but I need to then repeat the keyEvent somehow so that whatever was typed is actually entered. Any ideas?
So this is what I did:
itemList.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
if (e.keyCode == '\r' || e.keyCode == SWT.KEYPAD_CR) {
okButtonAction();
} else if (e.keyCode == SWT.ARROW_UP || e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.ARROW_LEFT || e.keyCode == SWT.ARROW_RIGHT) {
super.keyReleased(e);
} else if (e.character > 0) {
filterInput.setFocus();
Event event = new Event();
event.type = SWT.KeyDown;
event.keyCode = e.keyCode;
event.character = e.character;
Display.getCurrent().post(event);
try {
Thread.sleep(10);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
event.type = SWT.KeyUp;
Display.getCurrent().post(event);
}
}
});
I read that the Display.post method was there for doing automatic GUI testing, but it works for my purpose here, so I will use it unless anyone can give me a good reason why not??
My first idea was that there may be a way to re-fire the key event (or fire a copy of it) to the text field. But that may not yield the desired result, because there are some key events you probably don't want transferred from the list to the text, e.g. pressing the Up and Down arrow keys for navigation within the list.
So you should decide which key events trigger the focus transfer. From your question, I understand that you are implementing a text filter, so you should restrict the transfer to text characters. Once you know the character that was entered, you may append it to the filter text manually (or insert at the cursor position of the text field).

Categories