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....
Related
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
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();
}
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();
}
}
}
I'm trying to make a JSpinner that will only accepts numbers but I also want it to read/respond to backspace.
public class test {
JFrame frame;
JPanel panel;
JSpinner spinner;
public test()
{
frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(200,200));
panel = new JPanel();
SpinnerNumberModel numSpin = new SpinnerNumberModel(10, 0,1000,1);
spinner = new JSpinner(numSpin);
JFormattedTextField txt = ((JSpinner.NumberEditor) spinner.getEditor()).getTextField();
((NumberFormatter) txt.getFormatter()).setAllowsInvalid(false);
panel.add(spinner);
frame.setContentPane(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
test test = new test();
}
}
The code above works to make only numbers but this doesn't allow me to backspace. I found some examples on this site but they were written for C.
you are right JFormattedTextField isn't correctly implemented to JSpinner, you have implements DocumentFilter for filtering of un_wanted Chars typed from keyboad or pasted from ClipBoard, (thanks to #StanislavL)
you have solve by yourself issues with selectAll() on focusGained() wrapped into invokeLater(),
example
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.text.*;
public class TestDigitsOnlySpinner {
public static void main(String... args) {
SwingUtilities.invokeLater((Runnable) new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("enter digit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JSpinner jspinner = makeDigitsOnlySpinnerUsingDocumentFilter();
frame.getContentPane().add(jspinner, BorderLayout.CENTER);
frame.getContentPane().add(new JButton("just another widget"), BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
private JSpinner makeDigitsOnlySpinner_BasicAttempt() {
JSpinner spinner = new JSpinner(new SpinnerNumberModel());
return spinner;
}
private JSpinner makeDigitsOnlySpinnerUsingDocumentFilter() {
JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0, 20, 1));
JSpinner.NumberEditor jsEditor = (JSpinner.NumberEditor) spinner.getEditor();
final Document jsDoc = jsEditor.getTextField().getDocument();
if (jsDoc instanceof PlainDocument) {
AbstractDocument doc = new PlainDocument() {
private static final long serialVersionUID = 1L;
#Override
public void setDocumentFilter(DocumentFilter filter) {
if (filter instanceof MyDocumentFilter) {
super.setDocumentFilter(filter);
}
}
};
doc.setDocumentFilter(new MyDocumentFilter());
jsEditor.getTextField().setDocument(doc);
}
return spinner;
}
});
}
private static class MyDocumentFilter extends DocumentFilter {
#Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (stringContainsOnlyDigits(string)) {
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 {
if (stringContainsOnlyDigits(text)) {
super.replace(fb, offset, length, text, attrs);
}
}
private boolean stringContainsOnlyDigits(String text) {
for (int i = 0; i < text.length(); i++) {
if (!Character.isDigit(text.charAt(i))) {
return false;
}
}
return true;
}
}
private TestDigitsOnlySpinner() {
}
}
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!