I didn't find any java question that helped me solve my problem, so here I come.
I'm currently trying to use a NumberFormatter with a JFormattedTextField to format a price in a GUI as the user types it in.
But I'm getting strange results after typing 2 digits in the textfield.
Here the code I use to test (Netbeans 8.0 + JDK 1.7.0_51):
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator('.');
symbols.setGroupingSeparator(' ');
symbols.setCurrencySymbol("EUR");
DecimalFormat format = new DecimalFormat("¤ #,##0.00", symbols);
format.setMaximumFractionDigits(2);
format.setGroupingUsed(true);
NumberFormatter formatter = new NumberFormatter(format);
formatter.setMinimum( 0.00);
formatter.setMaximum(9_999.99);
formatter.setAllowsInvalid(false);
formatter.setOverwriteMode(true);
JFormattedTextField field = new JFormattedTextField(formatter);
field.setColumns(10);
field.setValue(0.33);
frame.add(field);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
What I expect :
// Step Text in TextField
// 1: GUI started EUR <caret>0.33
// 2: '1' pressed EUR 1<caret>.33
// 3: '2' pressed EUR 12<caret>.33
What I get :
// Step Text in TextField
// 1: start GUI EUR <caret>0.33 [OK]
// 2: press '1' EUR 1<caret>.33 [OK]
// 3: press '2' EUR 1 2<caret>33.00 [NOK, see expected result above]
To me it looks like the Formatter does (for step 3) :
insert '2' at the caret position -> EUR 12.33
remove all 'formatting characters' -> 1233
Formats the result of the "removal" again -> EUR 1 233.00
Is this the default behavior for the NumberFormatter?
If yes, am I missing something in the setup of the formatter or do I need to write a custom one?
If not, what am I doing wrong?
Regards,
Xan.
seems like as I'm haven't a.m., described issue, to test the setting for InputVerifier as is described in API ,
I'd suggest to use plain JTextField with DocumentFilter and the ISO name for currency to wrap by using NavigationFilter, e.g. excelent code example by camickr
.
import java.awt.*;
import java.math.*;
import java.text.*;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.JFormattedTextField.AbstractFormatterFactory;
import javax.swing.text.InternationalFormatter;
public class DocumentListenerAdapter {
public DocumentListenerAdapter() {
JFrame frame = new JFrame("AbstractTextField Test");
final JFormattedTextField textField1 = new JFormattedTextField(new Float(10.01));
textField1.setFormatterFactory(new AbstractFormatterFactory() {
#Override
public AbstractFormatter getFormatter(JFormattedTextField tf) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator('.');
symbols.setGroupingSeparator(' ');
symbols.setCurrencySymbol("EUR");
DecimalFormat format = new DecimalFormat("¤ #,##0.00", symbols);
format.setMaximumFractionDigits(2);
format.setGroupingUsed(true);
//NumberFormat format = DecimalFormat.getInstance();
format.setMinimumFractionDigits(2);
format.setMaximumFractionDigits(2);
format.setRoundingMode(RoundingMode.HALF_UP);
InternationalFormatter formatter = new InternationalFormatter(format);
formatter.setAllowsInvalid(false);
formatter.setMinimum(0.0);
formatter.setMaximum(9000.00);
return formatter;
}
});
NumberFormat numberFormat = NumberFormat.getNumberInstance();
numberFormat.setMaximumFractionDigits(2);
numberFormat.setMaximumFractionDigits(2);
numberFormat.setRoundingMode(RoundingMode.HALF_UP);
final JFormattedTextField textField2 = new JFormattedTextField(numberFormat);
textField2.setValue(new Float(10.01));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(textField1, BorderLayout.NORTH);
frame.add(textField2, BorderLayout.SOUTH);
frame.setVisible(true);
frame.pack();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new DocumentListenerAdapter();
}
});
}
}
Related
I am writing a restaurant application.
In this part, in order to add cook, user needs to enter cook's name in a nameTextField and cook's salary in a salaryTextField and at the name part I want to prevent the user from entering numbers and at the salary part I want to prevent the user from entering words. For salary part I tried to use exception handling but couldn't really succeed.
class AddButtonInCookClick implements ActionListener{
public void actionPerformed(ActionEvent e) {
String name = (String)nameTextFieldCook.getText();
double salary = new Double(0.0);
try {
salary = Double.parseDouble(salaryTextField.getText());
}catch(NumberFormatException ex) {
System.out.println(ex);
}
restaurant.getEmployees().add(new Cook(id, name, salary));
id++;
JOptionPane cookOptionPane = new JOptionPane();
JOptionPane.showMessageDialog(cookOptionPane, "Cook added succesfully.");
}
}
addButtonInCook.addActionListener(new AddButtonInCookClick());
Even though the program doesn't crush. I still can't make user enter numbers for salary part. Thank you for helping.
You can restrict input solely to numerals by using JFormattedTextField in lieu of a normal JTextField.
Sample code:
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import java.text.NumberFormat;
import javax.swing.text.NumberFormatter;
public class Test extends JFrame
{
JFormattedTextField salaryFormattedTextField;
NumberFormat numberFormat;
NumberFormatter numberFormatter;
public Test()
{
numberFormat = NumberFormat.getInstance();
// delete line if you want to see commas or periods grouping numbers based on your locale
numberFormat.setGroupingUsed(false);
numberFormatter = new NumberFormatter(format);
numberFormatter.setValueClass(Integer.class);
// delete line if you want to allow user to enter characters outside the value class.
// Deleting the line would allow the user to type alpha characters, for example.
// This pretty much defeats the purpose of formatting
numberFormatter.setAllowsInvalid(false);
salaryFormattedTextField = new JFormattedTextField(formatter);
this.add(salaryFormattedTextField);
}
public static void main(String[] args)
{
Test test = new Test();
s.pack();
s.setVisible(true);
}
}
The alternative, using the code structure you already have, is to throw up a JOptionPane when the input doesn't parse correctly.
try
{
salary = Double.parseDouble(salaryTextField.getText());
restaurant.getEmployees().add(new Cook(id, name, salary));
id++;
JOptionPane cookOptionPane = new JOptionPane();
JOptionPane.showMessageDialog(cookOptionPane, "Cook added succesfully.");
}
catch(NumberFormatException ex)
{
JOptionPane cookFailPane = new JOptionPane();
JOptionPane.showMessageDialog(cookFailPane , "Could not add cook. Please enter salary using only numeric input.");
ex.printStackTrace();
}
Alright I got something like this:
public void menu() {
final Form menu = new Form("Menu");
menu.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Button confirm = new Button("Confirm");
Container creditCardContainer = new Container(new GridLayout(1, 3));
final TextField num1 = new TextField(3);
final TextField num2 = new TextField(3);
final TextField num3 = new TextField(3);
num1.setConstraint(TextArea.NUMERIC);
num2.setConstraint(TextArea.NUMERIC);
num3.setConstraint(TextArea.NUMERIC);
creditCardContainer.addComponent(num1);
creditCardContainer.addComponent(num2);
creditCardContainer.addComponent(num3);
Validator v = new Validator();
v.addConstraint(num1, new LengthConstraint(2));
v.addConstraint(num2, new LengthConstraint(2));
v.addConstraint(num3, new LengthConstraint(4));
automoveToNext(num1, num2);
automoveToNext(num2, num3);
menu.add(creditCardContainer);
menu.add(confirm);
v.addSubmitButtons(confirm);
menu.show();
confirm.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
String getdate = num1.getText() + "/" + num2.getText() + "/" + num3.getText();
System.out.println(getdate);
new StateMachine("/theme");
}
});
}
}
private void automoveToNext(final TextField current, final TextField next) {
current.addDataChangedListener(new DataChangedListener() {
public void dataChanged(int type, int index) {
if(current.getText().length() == 3) {
Display.getInstance().stopEditing(current);
String val = current.getText();
current.setText(val.substring(0, 2));
next.setText(val.substring(2));
Display.getInstance().editString(next, 3, current.getConstraint(), next.getText());
}
}
});
}
Notice that addDataChangeListener is deprecated so I had to change it to addDataChangedListener instead.
I think there is something wrong in my code, because when I run it in the Codename One Simulator, it still allow me to type letters, even with the code below:
num1.setConstraint(TextArea.NUMERIC);
num2.setConstraint(TextArea.NUMERIC);
num3.setConstraint(TextArea.NUMERIC);
Also when I finish typing the date, my confirm button doesn't get highlighted as it should be. Please someone help me to fix it.
Obs: My date is intended to be dd/MM/yyyy
We don't support direct field masking as native text field input doesn't handle that very well. You have 2 options I can think of:
Use Date Picker which launches a great device native UI to pick the date. Notice it's not great in the simulator but on Android/iOS it would look good.
Use 3 text fields and automatically move to the next as you type like we did for this credit card input sample: http://www.codenameone.com/blog/validation-regex-masking.html
Using
try {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date date = format.parse("");
}catch (ParseException e) {
System.out.println("Wrong format.");
}
to check if the date is valid format.
im working on a java program using GUI, and i ran into a problem whenever i try to add the values from the text fields and one is missing it doesn't work and i get an error but if all of them are available i get the right answer, how can i add without having all the values?
JButton btnCheckOut = new JButton("CHECK OUT");
btnCheckOut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
double apples, strawberries, watermelon, tomatoe, carrot, beef, lamb, payment;
apples = Double.parseDouble(textField.getText());
strawberries = Double.parseDouble(textField_1.getText());
watermelon = Double.parseDouble(textField_2.getText());
tomatoe = Double.parseDouble(textField_3.getText());
carrot = Double.parseDouble(textField_4.getText());
beef = Double.parseDouble(textField_5.getText());
lamb = Double.parseDouble(textField_6.getText());
payment = (apples*8)+(strawberries*10)+(watermelon*14)+
(tomatoe*5)+(carrot*6)+(beef*25)+(lamb*20);
DecimalFormat df = new DecimalFormat("###.##");
textField_7.setText(String.valueOf(df.format(payment)));
}
});
Create e.g. getDoubleValue, which you apply to all your items when read. Simple as:
apples = getDoubleValue( textField.getText() );
...
...
then
public double getDoubleValue( String txt ) {
double d = 0d;
try {
if( txt != null && !txt.isEmpty() ) {
d = Double.parseDouble( txt );
}
} catch(Exception ex) {}
return d;
}
(This will also take care for "dirty input", if the textfield does not contain a number it will set it to zero during parse).
When you make your textFields, initialize the text there to 0. Like
JTextField textField_1 = new JTextField("0");
Or, you could add
if(textField.getText() == ""){
textField.setText("0");
}
For each text field before trying to parse to double.
Create an IF statement that sets the variables to zero if its respective TextField is empty, before you do the math operation.
if(textfield.getText().isEmpty())
{
apples = 0;
}
I am creating a project in which I am supposed to take date of birth of any person. So for that I have taken 3 combo boxes: date, month and year. But how I will know that the Date which is going to be inserted is valid because the number of day is different-different months and years is different.
And is there any ready made GUI component for taking dates from users?
I am designing using Swing package.
My sample code is
import java.awt.*;
import javax.swing.*;
public class Pro1 extends JFrame
{
JComboBox dd, mm, yy;
JLabel doblbl;
Container con;
public Pro1()
{
con = getContentPane();
doblbl = new JLabel("Date of Birth :-");
doblbl.setHorizontalAlignment(SwingConstants.CENTER);
doblbl.setFont(new Font("Arial",Font.BOLD,17));
doblbl.setForeground(Color.blue);
doblbl.setOpaque(true);
doblbl.setBackground(new Color(230,180,230));
dd = new JComboBox();
mm = new JComboBox();
yy = new JComboBox();
for(int i = 1; i<=31; i++)
dd.addItem("" + i);
for(int i = 1; i<=12; i++)
mm.addItem("" + i);
for(int i = 1960; i<=2014; i++)
yy.addItem("" + i);
con.setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
int i = 120;
doblbl.setBounds(30,i+=40,270,30);
int j = 120;
dd.setBounds(350,j+=40,50,30);
mm.setBounds(420,j,50,30);
yy.setBounds(480,j,70,30);
con.add(doblbl);
con.add(dd);
con.add(mm);
con.add(yy);
setSize(1500,800);
setVisible(true);
con.setBackground(new Color(125,80,140));
}
public static void main(String s[])
{
Pro1 p1 = new Pro1();
}
}
You can use SimpleDateFormat to parse or format the date as dd/MM/yyyy.
Sample code:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
String dateString = "30/02/2014"; // form date string in above format
String formattedDate = sdf.format(sdf.parse(dateString));
if (formattedDate.equals(dateString)) {
System.out.println("valid date");
} else {
System.out.println("Invalid date"); // It's an invalid date
}
Consider offering the user a JSpinner with a SpinnerDateModel, then it is easier for the user to enter, or scroll through and select, a valid date.
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class PromptForDate {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {}
SpinnerDateModel dateModel = new SpinnerDateModel(
new Date(), null, null, Calendar.DAY_OF_MONTH );
JSpinner dateSpinner = new JSpinner(dateModel);
dateSpinner.setEditor(
new JSpinner.DateEditor(dateSpinner, "dd/MM/yyyy"));
JOptionPane.showMessageDialog(
null, dateSpinner, "D.O.B.?",
JOptionPane.QUESTION_MESSAGE);
System.out.println(dateModel.getValue());
}
};
SwingUtilities.invokeLater(r);
}
}
And is there any ready made GUI component for taking dates from users?
Yes, there are several options in standard API and third-party libraries, as exposed in this answer: JSpinner + SpinnerDateModel or JCalendar or JXDatePicker. These components will also solve this other problem:
But how i will know that the date which is going to be inserted is
valid because the number of dates in different-different months and
years is different.
Off-topic
About this:
con.setLayout(null);
...
dd.setBounds(350,j+=40,50,30);
mm.setBounds(420,j,50,30);
yy.setBounds(480,j,70,30);
...
con.add(dd);
con.add(mm);
con.add(yy);
While using Null layout is perfectly possible, Swing is designed to be used along with layout managers and thus null layout is discouraged. See this topic Why is it frowned upon to use a null layout in SWING?.
How do I code a JFormattedTextField to accept a currency format without decimals?
I have tried looking for my answer everywhere. Here, Oracle, Google, and Code Ranch to be specific.
My question: How do I code a formatted text field to accept a currency format without decimals. The text field can accept a value anywhere from $5 to $10,000,000. I would like it to include the "," when need. This field will not be used for mathematical expressions so there is no need to convert it from a string.
Here is the code that I am trying to use. This format is not allowing me to enter any digits at all in the formatted text field.
buildInfo method
//The buildInfo method will build the info panel
private void buildInfo()
{
info = new JPanel();
GridLayout gl = new GridLayout (3,1);
info.setLayout (gl);
//Create panel, label, and text area for pledgers name
p1 = new JPanel();
p1.setLayout(new FlowLayout(FlowLayout.LEFT));
label1 = new JLabel ("Pledger's Name: ");
p1.add (label1);
text1 = new JTextField (20);
p1.add (text1);
//Create panel, label, and text area for pledge amount
p2 = new JPanel();
p2.setLayout(new FlowLayout(FlowLayout.LEFT));
label2 = new JLabel ("Pledged Amount: ");
p2.add (label2);
NumberFormat amount = NumberFormat.getCurrencyInstance(Locale.US);
amount.setMaximumFractionDigits(0);
NumberFormatter pAmount = new NumberFormatter(amount);
pAmount.setMinimum(5.0);
pAmount.setMaximum(10000000.0);
pAmount.setAllowsInvalid(false);
text2 = new JFormattedTextField (pAmount);
text2.setColumns(12);
p2.add (text2);
//Create panel, label, and text area for charity being pledged
p3 = new JPanel();
p3.setLayout(new FlowLayout(FlowLayout.LEFT));
label3 = new JLabel ("Charity Pledged To:");
p3.add (label3);
text3 = new JTextField (20);
p3.add (text3);
//Add panels to main panel
add(p1);
add(p2);
add(p3);
}
Use
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US);
format.setMaximumFractionDigits(0);
NumberFormatter formatter = new NumberFormatter(format);
formatter.setMinimum(5.0);
formatter.setMaximum(10000000.0);
formatter.setAllowsInvalid(false);
formatter.setOverwriteMode(true);
JFormattedTextField field = new JFormattedTextField(formatter);
field.setValue(5.0);