D
Dmitri
Hello, guys
I'm trying to create a text field where I could enter any valid
digits for percents (let's say -900 .. 900) and have it displayed
with '%' sign, when the field looses focus or ENTER is pressed.
I am using NumberFormat.getPercentInstance() to get formatter and
it displays the initial value fine (with '%' sign). I limit my
input to digits with PercentInputFilter. The problem is, when I
delete the current contents of the field, enter my new value
(let's say 50) and click the button the value is not accepted
and reverted to the previous one. As far as I understand, with
getPercentInstance() it requires '%' char to be present. But
what I'm trying to achieve is to enter digits and have '%' to
be automatically displayed (if it's not there yet).
I am browsing doc on JFormattedText field, but could come up
with a good solution to meed my above mentioned needs.
Any suggestions, help, sample code are appreciated.
See sample code below. You can actually compile and run it
to see the problem.
Thanks
-Dmitri
<sample_code>
import javax.swing.JFormattedTextField;
import java.text.NumberFormat;
import javax.swing.text.DocumentFilter;
import javax.swing.text.BadLocationException;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
public class SpeedField extends JFormattedTextField {
public static final int DEFAULT_COLUMNS = 11;
public static final double DEFAULT_VALUE = 1.00; // 100%
public SpeedField() {
//super(NumberFormat.getPercentInstance());
super();
setColumns(DEFAULT_COLUMNS);
setHorizontalAlignment(javax.swing.JTextField.RIGHT);
NumberFormatter formatter =
new NumberFormatter (NumberFormat.getPercentInstance()) {
protected DocumentFilter getDocumentFilter() {
return filter;
}
private DocumentFilter filter = new PercentInputFilter();
};
DefaultFormatterFactory dff = new DefaultFormatterFactory();
dff.setDefaultFormatter(formatter);
dff.setDisplayFormatter(formatter);
dff.setEditFormatter(formatter);
setFormatterFactory(dff);
setValue(new Double(DEFAULT_VALUE));
}
protected int getColumnWidth() {
return getFontMetrics(getFont()).charWidth('0');
}
private class PercentInputFilter extends DocumentFilter {
public void insertString(FilterBypass fb,
int offset,
String string,
AttributeSet attr) throws BadLocationException {
StringBuffer buffer = new StringBuffer(string);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isDigit(ch) && ch != '-')
buffer.deleteCharAt(i);
}
super.insertString(fb, offset, buffer.toStri343ng(), attr);
}
public void replace(FilterBypass fb,
int offset,
int length,
String string,
AttributeSet attr) throws BadLocationException {
if (string != null) {
StringBuffer buffer = new StringBuffer(string);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isDigit(ch) && ch != '-')
buffer.deleteCharAt(i);
}
string = buffer.toString();
}
super.replace(fb, offset, length, string, attr);
}
} // class PercentInputField
/** -----------------------------------------------------------------------
* TEST UNIT
*/
public static void main(String[] argv) {
javax.swing.JFrame frame = new javax.swing.JFrame("SpeedField Test");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
final SpeedField speed = new SpeedField();
javax.swing.JPanel p = new javax.swing.JPanel();
p.add(speed);
javax.swing.JButton btValue = new javax.swing.JButton("Value");
btValue.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
System.err.println("value = " + speed.getValue());
}
});
p.add(btValue);
frame.getContentPane().add(p, java.awt.BorderLayout.NORTH);
frame.pack();
frame.setSize(new java.awt.Dimension(200, 80));
frame.setLocation(100,100);
frame.setVisible(true);
}
} // class SpeedField
</sample_code>
I'm trying to create a text field where I could enter any valid
digits for percents (let's say -900 .. 900) and have it displayed
with '%' sign, when the field looses focus or ENTER is pressed.
I am using NumberFormat.getPercentInstance() to get formatter and
it displays the initial value fine (with '%' sign). I limit my
input to digits with PercentInputFilter. The problem is, when I
delete the current contents of the field, enter my new value
(let's say 50) and click the button the value is not accepted
and reverted to the previous one. As far as I understand, with
getPercentInstance() it requires '%' char to be present. But
what I'm trying to achieve is to enter digits and have '%' to
be automatically displayed (if it's not there yet).
I am browsing doc on JFormattedText field, but could come up
with a good solution to meed my above mentioned needs.
Any suggestions, help, sample code are appreciated.
See sample code below. You can actually compile and run it
to see the problem.
Thanks
-Dmitri
<sample_code>
import javax.swing.JFormattedTextField;
import java.text.NumberFormat;
import javax.swing.text.DocumentFilter;
import javax.swing.text.BadLocationException;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
public class SpeedField extends JFormattedTextField {
public static final int DEFAULT_COLUMNS = 11;
public static final double DEFAULT_VALUE = 1.00; // 100%
public SpeedField() {
//super(NumberFormat.getPercentInstance());
super();
setColumns(DEFAULT_COLUMNS);
setHorizontalAlignment(javax.swing.JTextField.RIGHT);
NumberFormatter formatter =
new NumberFormatter (NumberFormat.getPercentInstance()) {
protected DocumentFilter getDocumentFilter() {
return filter;
}
private DocumentFilter filter = new PercentInputFilter();
};
DefaultFormatterFactory dff = new DefaultFormatterFactory();
dff.setDefaultFormatter(formatter);
dff.setDisplayFormatter(formatter);
dff.setEditFormatter(formatter);
setFormatterFactory(dff);
setValue(new Double(DEFAULT_VALUE));
}
protected int getColumnWidth() {
return getFontMetrics(getFont()).charWidth('0');
}
private class PercentInputFilter extends DocumentFilter {
public void insertString(FilterBypass fb,
int offset,
String string,
AttributeSet attr) throws BadLocationException {
StringBuffer buffer = new StringBuffer(string);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isDigit(ch) && ch != '-')
buffer.deleteCharAt(i);
}
super.insertString(fb, offset, buffer.toStri343ng(), attr);
}
public void replace(FilterBypass fb,
int offset,
int length,
String string,
AttributeSet attr) throws BadLocationException {
if (string != null) {
StringBuffer buffer = new StringBuffer(string);
for (int i = buffer.length() - 1; i >= 0; i--) {
char ch = buffer.charAt(i);
if (!Character.isDigit(ch) && ch != '-')
buffer.deleteCharAt(i);
}
string = buffer.toString();
}
super.replace(fb, offset, length, string, attr);
}
} // class PercentInputField
/** -----------------------------------------------------------------------
* TEST UNIT
*/
public static void main(String[] argv) {
javax.swing.JFrame frame = new javax.swing.JFrame("SpeedField Test");
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
final SpeedField speed = new SpeedField();
javax.swing.JPanel p = new javax.swing.JPanel();
p.add(speed);
javax.swing.JButton btValue = new javax.swing.JButton("Value");
btValue.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
System.err.println("value = " + speed.getValue());
}
});
p.add(btValue);
frame.getContentPane().add(p, java.awt.BorderLayout.NORTH);
frame.pack();
frame.setSize(new java.awt.Dimension(200, 80));
frame.setLocation(100,100);
frame.setVisible(true);
}
} // class SpeedField
</sample_code>