Trying to use key Listener - java

I have a program that implements keyListener. What I'm trying to do is only allow digits, backspace key, decimal key, and back arrow key to be pressed. Everything works except when I pressed the back arrow key it deletes the numbers I input`
public void keyReleased(KeyEvent e) {
try{
if(!Character.isDigit(e.getKeyChar()) && e.getKeyChar() != '.' && e.getKeyChar() != e.VK_BACK_SPACE && e.getKeyChar() != KeyEvent.VK_LEFT){
String input = inputIncome.getText();
inputIncome.setText(input.substring(input.length()-1));
}
}
catch(Exception arg){
}`

KeyListener rules...
Don't use KeyListener for components which don't require focus to be activated, even then, use Key Bindings instead
Don't use KeyListener on text components, use a DocumentFilter instead
Based on the fact that you seem to be changing the contents of, what I assume is, a JTextField or text component, you should be using a DocumentFilter to filter the changes been sent to the fields Document, for example...
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
public class DocumentFilterExample {
public static void main(String[] args) {
new DocumentFilterExample();
}
public DocumentFilterExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTextField field = new JTextField(10);
((AbstractDocument)field.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(field);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DecimalDocumentFilter extends DocumentFilter {
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr)
throws BadLocationException {
Document doc = fb.getDocument();
boolean hasDot = doc.getText(0, doc.getLength()).contains(".");
StringBuilder buffer = new StringBuilder(text);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isDigit(ch)) {
if ((ch == '.' && !hasDot)) {
hasDot = true;
} else {
buffer.deleteCharAt(i);
}
}
}
super.insertString(fb, offset, buffer.toString(), attr);
}
#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);
}
}
}
This is based on the examples here.
There are number of reasons for not using a KeyListener in this way, for example...
You can't guarantee the order in which the listeners are activated, it's entirely possible that the event may be consumed before it reaches you or the content has not yet been added to the field's Document
It doesn't take into account what happens when you paste text into the field
It could cause a mutation exception as the document is been updated while you're trying to change it...
Just to name a few

Related

How to generate html for text in JTextArea?

I have a problem in generating html code for a given string which is from
JTextArea textArea=new JTextArea(10,10);
String textToHtml=textArea.getText();
In this generated html code, it should contain with all html tags which are related to the given string.
Like <p>something like this</p>, <br> and etc.
Also this is not a web application. If you have any idea how do this. Suggest me. Thanks.
Update
For an example, if I type a text with line breaks, it should automatically insert <br> or <p>. This kind of function is available in Dreamweaver. It automatically inserts the code when you start filling the content in the webpage. The issue is so I don't want the non-technical usres to type the HTML code when they are writing paragraphs, because by default the tag and all are inserted. I will be emailing this directly to the user after this text is typed, so this formatting is essential.
It is important to note that I don't know what the user will type, it is all upto him. so whatever the method I use should be capable of identfying the places where it could put tags (like paragraph tag) and move on
For an example, if I type a text with line breaks, it should automatically insert <br> or <p>
The basic requirement would be to use a DocumentFilter to inject your markup when ever they type enter
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class TestMarkup {
public static void main(String[] args) {
new TestMarkup();
}
public TestMarkup() {
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 static class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTextArea ta = new JTextArea(10, 20);
add(new JScrollPane(ta));
((AbstractDocument) ta.getDocument()).setDocumentFilter(new DocumentFilter() {
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (text.endsWith("\n")) {
super.replace(fb, offset, 0, "<br>", attrs);
offset += 4;
}
super.replace(fb, offset, length, text, attrs);
}
});
}
}
}
Inserting <p>/</p> "might" be more difficult, but, if you assume that your first line starts with <p>, it's just a matter of inject </p> before the newline and <p> after it, then append the remaining text...
Updated with Paragraph support and pasting
Apparently I just can't walk away...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.StringJoiner;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.Element;
public class TestMarkup {
public static void main(String[] args) {
new TestMarkup();
}
public TestMarkup() {
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 static class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTextArea ta = new JTextArea(10, 20);
add(new JScrollPane(ta));
((AbstractDocument) ta.getDocument()).setDocumentFilter(new DocumentFilter() {
protected String getLastLineOfText(Document document) throws BadLocationException {
// Find the last line of text...
Element rootElem = document.getDefaultRootElement();
int numLines = rootElem.getElementCount();
Element lineElem = rootElem.getElement(numLines - 1);
int lineStart = lineElem.getStartOffset();
int lineEnd = lineElem.getEndOffset();
String lineText = document.getText(lineStart, lineEnd - lineStart);
return lineText;
}
#Override
public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (text.length() > 1) {
String lastLineOfText = getLastLineOfText(fb.getDocument());
if (!lastLineOfText.startsWith("<p>")) {
if (!text.startsWith("<p>")) {
text = "<p>" + text;
}
}
// Replace any line breaks with a new line
String[] lines = text.split("\n");
if (lines.length > 0) {
StringJoiner sj = new StringJoiner("<br>\n");
for (String line : lines) {
sj.add(line);
}
text = sj.toString();
}
if (!text.endsWith("</p>")) {
text += "</p>";
}
super.replace(fb, offset, length, text, attrs);
} else {
String postInsert = null;
if (text.endsWith("\n")) {
// Find the last line of text...
String lastLineOfText = getLastLineOfText(fb.getDocument());
lastLineOfText = lastLineOfText.substring(0, lastLineOfText.length() - 1);
postInsert = "<p>";
if (!lastLineOfText.endsWith("</p>")) {
super.replace(fb, offset, 0, "</p>", attrs);
offset += 4;
}
}
super.replace(fb, offset, length, text, attrs);
if (postInsert != null) {
offset += text.length();
super.replace(fb, offset, 0, "<p>", attrs);
}
}
}
});
}
}
}
Maybe you need something like this:
String textToHtml="something like this";
textToHtml = "<p>".concat(textToHtml).concat("</p>").concat("<br>");

Alphabets validation of jtextfield

I have been trying to just display the alphabets in the jtextfield.Even though the other keys are pressed the jtextfield should not display them only the alphabets are to be displayed.can you please help me with this..
Start by taking a look at Implementing a Document Filter
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class TestFilter {
public static void main(String[] args) {
new TestFilter();
}
public TestFilter() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JTextField field = new JTextField(10);
((AbstractDocument)field.getDocument()).setDocumentFilter(new CharFilter());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(field);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CharFilter extends DocumentFilter {
#Override
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String string, AttributeSet attr)
throws BadLocationException {
StringBuilder buffer = new StringBuilder(string);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isAlphabetic(ch)) {
buffer.deleteCharAt(i);
}
}
super.insertString(fb, offset, buffer.toString(), attr);
}
#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);
}
}
}
You ma also find DocumentFilter Examples helpful
here is a solution if you want only alphabets to be entered to a jtextfield,and no other keys should be entered even though they get pressed.in your jframe just select your jtextfield rightclick on jtextfield you will find events and then go to events click on keyTyped event and then write the following code to enter only the alphabets into your jtextfield.
private void tfempidKeyTyped(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
char key = evt.getKeyChar();
if (key > '0' && key < '9') {
evt.consume();
}

JTextArea - enable edit only at the end of document

I use a JTextArea where using double click I can able to select the word at any place but I don't want to enable edit. Which means text can be entered only at the end of text area and not anywhere in between.
I have tried with mouse listeners like below:
#Override
public void mouseClicked(MouseEvent me) {
if(SwingUtilities.isLeftMouseButton(me)){
System.err.println("clicked");
int pos = textArea.getCaretPosition();
if(pos < textArea.getDocument().getLength()){
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
}
This makes double click not to select the word. I understand it is because caret position is moved to end. But how can I achieve this?
Check out the Protected Text Component which allows you to protect multiple areas of a Document from change.
Or if you don't need to be able to "select" any of the protected text than a simpler solution is to use a NavigationFilter:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class NavigationFilterPrefixWithBackspace extends NavigationFilter
{
private int prefixLength;
private Action deletePrevious;
public NavigationFilterPrefixWithBackspace(int prefixLength, JTextComponent component)
{
this.prefixLength = prefixLength;
deletePrevious = component.getActionMap().get("delete-previous");
component.getActionMap().put("delete-previous", new BackspaceAction());
component.setCaretPosition(prefixLength);
}
#Override
public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias)
{
fb.setDot(Math.max(dot, prefixLength), bias);
}
#Override
public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias)
{
fb.moveDot(Math.max(dot, prefixLength), bias);
}
class BackspaceAction extends AbstractAction
{
#Override
public void actionPerformed(ActionEvent e)
{
JTextComponent component = (JTextComponent)e.getSource();
if (component.getCaretPosition() > prefixLength)
{
deletePrevious.actionPerformed( null );
}
}
}
private static void createAndShowUI()
{
JTextField textField = new JTextField("Prefix_", 20);
textField.setNavigationFilter( new NavigationFilterPrefixWithBackspace(7, textField) );
JFrame frame = new JFrame("Navigation Filter Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(textField);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Okay, this is slightly hacky...
Basically what this does is installs a "protected" DocumentFilter, which will only allow input to put in from a certain point in the Document.
It overrides the JTextArea's insert-break key binding (Enter) and records a marker. The "protected" DocumentFilter then ensures that the content does not precede this point
I was forced to implement a KeyListener on the field to move the cursor to the end of the input, while the DocumentFilter was capable of handling this, it did present some issues with deleting and general usability. This also ensures that the selection is un-highlighted when new content is added...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class Terminal {
public static void main(String[] args) {
new Terminal();
}
public Terminal() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTextArea terminal = new JTextArea(20, 40);
ProtectedDocumentFilter.install(terminal);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(terminal));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static interface UserInput {
public int getUserInputStart();
public void setUserInputStart(int lastPoint);
}
public static class DefaultUserInput implements UserInput {
private final JTextArea textArea;
private int userInputStart;
public DefaultUserInput(JTextArea ta) {
textArea = ta;
ActionMap am = ta.getActionMap();
Action action = am.get("insert-break");
am.put("insert-break", new ProxyAction(action));
ta.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (textArea.getCaretPosition() != textArea.getDocument().getLength()) {
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
});
}
#Override
public void setUserInputStart(int userInputStart) {
this.userInputStart = userInputStart;
}
#Override
public int getUserInputStart() {
return userInputStart;
}
public class ProxyAction extends AbstractAction {
private final Action proxy;
public ProxyAction(Action proxy) {
this.proxy = proxy;
}
#Override
public void actionPerformed(ActionEvent e) {
proxy.actionPerformed(e);
int range = textArea.getCaretPosition() - userInputStart;
userInputStart += range;
}
}
}
public static class ProtectedDocumentFilter extends DocumentFilter {
protected static void install(JTextArea textArea) {
UserInput ui = new DefaultUserInput(textArea);
((AbstractDocument) textArea.getDocument()).setDocumentFilter(new ProtectedDocumentFilter(ui));
}
private UserInput userInput;
public ProtectedDocumentFilter(UserInput userInput) {
this.userInput = userInput;
}
public UserInput getUserInput() {
return userInput;
}
#Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (offset < getUserInput().getUserInputStart()) {
offset = fb.getDocument().getLength();
}
System.out.println("Insert");
super.insertString(fb, offset, string, attr);
}
#Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.remove(fb, offset, length);
}
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (offset < getUserInput().getUserInputStart()) {
offset = fb.getDocument().getLength();
length = 0;
}
super.replace(fb, offset, length, text, attrs);
if (text.contains("\n")) {
int lastPoint = offset + text.lastIndexOf("\n");
if (lastPoint > getUserInput().getUserInputStart()) {
getUserInput().setUserInputStart(lastPoint + 1);
}
}
}
}
}
This is just an example, you're going to need to play with it and tweak it to meet your own needs....

Restricting JTextField for only numbers

I'm making a small app where I have two text fields. But I want it to be that when the user insert something that is not a number, it gives an alert message. I have done it like below but it does not work. I have tried tp use try & catch. Can anyone help me with this?
public void actionPerformed(ActionEvent ngjarja)
{
String rresht = teksti1.getText();
int rreshtii = Integer.parseInt(rresht);//kthimi i stringut ne integer
String shtyll = teksti2.getText();
int shtylle = Integer.parseInt(shtyll);
if (ngjarja.getSource()== mat)
mbushMatricenString(rreshtii,shtylle); //Thirr metoden
if (ngjarja.getSource()== buton1)
mbushVektorinString1( rreshtii,shtylle);
try { Integer.parseInt(teksti1.getText());
Integer.parseInt(teksti2.getText());
} catch (NumberFormatException e) {
JOptionPane.showConfirmDialog(null, "Please enter numbers only", "naughty", JOptionPane.CANCEL_OPTION);
}
}
The problem is ActionListener will only be called when the user "actions" the field (typically by pressing Enter)
You could...
Use a InputVerfier which allows you to verify the state of the field.
Take a look at Validting Input for more details...
You Could...
Use a DocumentFilter to actually prevent the user from entering anything you didn't want them to.
Take a look at Implementing a Document Filter and MDP's Weblog for examples...
You Could...
Use a JSpinner instead
Have a look at this example this only accepts number from user and displayed appropriate error message in JOptionPane.
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
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 Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField jtf = new JTextField();
//add filter to document
((AbstractDocument) jtf.getDocument()).setDocumentFilter(new MyDocumentFilter());
frame.add(jtf);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyDocumentFilter extends DocumentFilter {
#Override
public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {
for (int n = string.length(); n > 0; n--) {//an inserted string may be more than a single character i.e a copy and paste of 'aaa123d', also we iterate from the back as super.XX implementation will put last insterted string first and so on thus 'aa123d' would be 'daa', but because we iterate from the back its 'aad' like we want
char c = string.charAt(n - 1);//get a single character of the string
System.out.println(c);
if (Character.isDigit(c)) {//if its an alphabetic character or white space
super.replace(fb, i, i1, String.valueOf(c), as);//allow update to take place for the given character
} else {//it was not an alphabetic character or white space
System.out.println("Not allowed");
JOptionPane.showMessageDialog(null, "Only Numbers are allowed");
}
}
}
#Override
public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
super.remove(fb, i, i1);
}
#Override
public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
super.insertString(fb, i, string, as);
}
}
Use This:
public class CustomTextField extends JTextField implements KeyListener{
public CustomTextField() {
super();
addKeyListener(this);
}
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent event) {
char c = event.getKeyChar();
if (!(Character.isDigit(c) || c == KeyEvent.VK_BACK_SPACE || c== KeyEvent.VK_DELETE)) {
event.consume();
}
}
}

How to display a temporary baloon tooltip during input validation?

I'm somewhat used to the GUI idiom where when I type something wrong in a text input field a balloon pops up from the field with info about what I got wrong / expected input. It remains visible until I type again.
But now I couldn't find any example to point to.
Given a JTextfield do you know of any library/code that would display such a balloon when triggered by my keylistener?
#see http://www.javapractices.com/topic/TopicAction.do?Id=151
Balloon Tip is a library that does that:
balloonTip = new BalloonTip(f, "Tooltip msg");
That was all needed! If you insist on a having it be a tooltip too:
tooltipBalloon = new BalloonTip(someComponent, "I'm a balloon tooltip!");
// Now convert this balloon tip to a tooltip, such that the tooltip shows up after 500 milliseconds and stays visible for 3000 milliseconds
ToolTipUtils.balloonToToolTip(tooltipBalloon, 500, 3000);
The link given by James Poulson probably provides a better solution, but I had to see if this were possible with some simple Java code using a DocumentFilter and a JWindow. Here's one possible way to do this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Window;
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 InfoBalloon extends JPanel {
private static final int PREF_WIDTH = 400;
private static final int PREF_HEIGHT = 300;
private static final String REGEX_TEST = "\\d*";
private static final String ERROR_TEXT = "Please only add numbers to the text field";
private JTextField textField = new JTextField(10);
private JWindow errorWindow;
public InfoBalloon() {
add(new JLabel("Please Enter Number"));
add(textField);
((PlainDocument)textField.getDocument()).setDocumentFilter(new MyNumberDocFilter());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
private void showErrorWin() {
if (errorWindow == null) {
JLabel errorLabel = new JLabel(ERROR_TEXT);
Window topLevelWin = SwingUtilities.getWindowAncestor(this);
errorWindow = new JWindow(topLevelWin);
JPanel contentPane = (JPanel) errorWindow.getContentPane();
contentPane.add(errorLabel);
contentPane.setBackground(Color.white);
contentPane.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
errorWindow.pack();
}
Point loc = textField.getLocationOnScreen();
errorWindow.setLocation(loc.x + 20, loc.y + 30);
errorWindow.setVisible(true);
}
private boolean textOK(String text) {
if (text.matches(REGEX_TEST)) {
return true;
}
return false;
}
private class MyNumberDocFilter extends DocumentFilter {
#Override
public void insertString(FilterBypass fb, int offset, String string,
AttributeSet attr) throws BadLocationException {
if (textOK(string)) {
super.insertString(fb, offset, string, attr);
if (errorWindow != null && errorWindow.isVisible()) {
errorWindow.setVisible(false);
}
} else {
showErrorWin();
}
}
#Override
public void replace(FilterBypass fb, int offset, int length, String text,
AttributeSet attrs) throws BadLocationException {
if (textOK(text)) {
super.replace(fb, offset, length, text, attrs);
if (errorWindow != null && errorWindow.isVisible()) {
errorWindow.setVisible(false);
}
} else {
showErrorWin();
}
}
#Override
public void remove(FilterBypass fb, int offset, int length)
throws BadLocationException {
super.remove(fb, offset, length);
if (errorWindow != null && errorWindow.isVisible()) {
errorWindow.setVisible(false);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Info Balloon");
frame.getContentPane().add(new InfoBalloon());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Constructive or destructive criticism is most welcome!

Categories