Related
It surprise me!
According to the document of groovy, groovy may use "getProperty" method to get the property of a object. So when I want to change the behavier of getting property on the special object, I use a category class to override the "getProperty" method. However, it does not work.
At last, I found groovy framework use the "get" method in the category class to get property, even if the object is not a map.
My question is that is it a bug or groovy just work like that.
This is the category class.
class DynaBeanExtension {
public static void setProperty(DynaBean bean, String propertyName, def newValue) {
try {
PropertyUtilsBean pu = null;
if (bean instanceof CustomWrapDynaBean) {
pu = bean.propertyUtilsBean;
}
if (pu != null) {
pu.setProperty(bean, propertyName, newValue);
} else {
PropertyUtils.setProperty(bean, propertyName, newValue);
}
} catch (IllegalArgumentException ex) {
bean.propertyMissing(propertyName, newValue);
}
}
public static def getProperty(DynaBean bean, String propertyName) {
try {
PropertyUtilsBean pu = null;
if (bean instanceof CustomWrapDynaBean) {
pu = bean.propertyUtilsBean;
}
if (pu != null) {
return pu.getProperty(bean, propertyName);
} else {
return PropertyUtils.getProperty(bean, propertyName);
}
} catch (IllegalArgumentException ex) {
return bean.propertyMissing(propertyName);
}
}
public static def get(DynaBean bean, String propertyName) {
try {
PropertyUtilsBean pu = null;
if (bean instanceof CustomWrapDynaBean) {
pu = bean.propertyUtilsBean;
}
if (pu != null) {
return pu.getProperty(bean, propertyName);
} else {
return PropertyUtils.getProperty(bean, propertyName);
}
} catch (IllegalArgumentException ex) {
return bean.propertyMissing(propertyName);
}
}
This is the test code:
public static class TestSubClass {
private final int e = 3, f = 4;
private final Map<String, Object> m = new HashMap<>();
public int getE() {
return e;
}
public int getF() {
return f;
}
public Map<String, Object> getM() {
return m;
}
#Override
public String toString() {
return "TestSubClass{" + "e=" + e + ", f=" + f + ", m=" + m + '}';
}
}
public static class TestClass {
private final int a = 1;
private final TestSubClass b = new TestSubClass();
public int getA() {
return a;
}
public TestSubClass getB() {
return b;
}
#Override
public String toString() {
return "TestClass{" + "a=" + a + ", b=" + b + '}';
}
}
Map<String, String> pMap = new HashMap<>();
pMap.put("b.e", "c");
PropertyUtilsBean pu = new PropertyUtilsBean();
pu.setResolver(new ExResolver(pMap));
TestClass testObj = new TestClass();
DynaBean bean = new CustomWrapDynaBean(testObj, pu);
int c = use(DynaBeanExtension) {
bean.c;
}
This is the code of ExResolver:
public class ExResolver implements Resolver {
private static final char NESTED = '.';
private static final char MAPPED_START = '(';
private static final char MAPPED_END = ')';
private static final char INDEXED_START = '[';
private static final char INDEXED_END = ']';
private final Resolver resolver;
private final Map<String, String> pMap;
public ExResolver(Map<String, String> pMap) {
this(new DefaultResolver(), pMap);
}
public ExResolver(Resolver resolver, Map<String, String> pMap) {
this.resolver = resolver;
this.pMap = new HashMap<>(pMap);
}
private String resolveExpr(String expression) {
for (Map.Entry<String, String> entry : pMap.entrySet()) {
if (expression.startsWith(entry.getValue())) {
String to = entry.getValue();
if (expression.length() == entry.getValue().length()) {
return entry.getKey();
} else {
int toTest = expression.codePointAt(to.length());
if (toTest == NESTED || toTest == MAPPED_START || toTest == INDEXED_START) {
return entry.getKey() + expression.substring(to.length(), expression.length());
} else {
return expression;
}
}
}
}
return expression;
}
#Override
public int getIndex(String expression) {
expression = resolveExpr(expression);
return resolver.getIndex(expression);
}
#Override
public String getKey(String expression) {
expression = resolveExpr(expression);
return resolver.getKey(expression);
}
#Override
public String getProperty(String expression) {
expression = resolveExpr(expression);
return resolver.getProperty(expression);
}
#Override
public boolean hasNested(String expression) {
expression = resolveExpr(expression);
return resolver.hasNested(expression);
}
#Override
public boolean isIndexed(String expression) {
expression = resolveExpr(expression);
return resolver.isIndexed(expression);
}
#Override
public boolean isMapped(String expression) {
expression = resolveExpr(expression);
return resolver.isMapped(expression);
}
#Override
public String next(String expression) {
expression = resolveExpr(expression);
return resolver.next(expression);
}
#Override
public String remove(String expression) {
expression = resolveExpr(expression);
return resolver.remove(expression);
}
}
"get" is invoked, not "getProperty"
What's more, in the real situation DynaBeanExtension is compiled with groovy. The construction of bean is compiled with java. Then by using binding, I put it into the test code which is a runtime script executed by java code.
This happens in the compilation itself. Let's look at a simpler example.
class Main {
static void main(def args) {
Foo foo = new Foo()
foo.str = ""
foo.str
}
}
For Groovy classes
class Foo {
String str
}
If you decompile the Main class, you'll see it is
public class Main implements GroovyObject {
public Main() {
Main this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
MetaClass localMetaClass = $getStaticMetaClass();
this.metaClass = localMetaClass;
}
public static void main(String... args) {
CallSite[] arrayOfCallSite = $getCallSiteArray();
Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class), Foo.class);
String str = "";
ScriptBytecodeAdapter.setGroovyObjectProperty(str, Main.class, foo, (String)"str");
arrayOfCallSite[1].callGroovyObjectGetProperty(foo);
}
}
A .[property] = call gets compiled to a ScriptBytecodeAdapter.setGroovyObjectProperty, that in turn calls the chain MetaClassImpl.setProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [setter]
And a .[property] call gets compiled to a arrayOfCallSite[1].callGroovyObjectGetProperty, that in turn calls the chain
AbstractCallSite.callGroovyObjectGetProperty > GetEffectivePogoPropertySite.getProperty > MethodMetaProperty$GetBeanMethodMetaProperty.getProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [getter]
For Java classes
If you use a Java version of the class being called, like this
public class Foo {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
The same Main decompiles to
public class Main implements GroovyObject {
public Main() {
Main this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
MetaClass localMetaClass = $getStaticMetaClass();
this.metaClass = localMetaClass;
}
public static void main(String... args) {
CallSite[] arrayOfCallSite = $getCallSiteArray();
Foo foo = (Foo)ScriptBytecodeAdapter.castToType(arrayOfCallSite[0].callConstructor(Foo.class), Foo.class);
String str = "";
ScriptBytecodeAdapter.setProperty(str, null, foo, (String)"str");
arrayOfCallSite[1].callGetProperty(foo);
}
}
A .[property] = call gets compiled to a ScriptBytecodeAdapter.setProperty, that in turn calls the chain [Class].setProperty > InvokerHelper.setProperty -> MetaClassImpl.setProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [setter]
And a .[property] call gets compiled to a arrayOfCallSite[1].callGroovyObjectGetProperty, that in turn calls the chain
AbstractCallSite.callGetProperty > GetEffectivePojoPropertySite.getProperty > MethodMetaProperty$GetBeanMethodMetaProperty.getProperty > MetaMethod.doMethodInvoke > CachedMethod.invoke > java.lang.reflect.Method.invoke > [getter]
To correct your code
As you can see from these dispatch chains, you've overridden the getter correctly (since it happens in the class itself), but if you want to override getProperty or setProperty, you have to do this in metaClass, and not the class itself. The behavior you're seeing is expected. This code demonstrates how to override each
class Foo {
String bar
}
// override using setter in category
#Category(Foo)
class FooCategory {
public String getBar() {
println "in getter"
}
public void setBar(String bar) {
println "in setter"
}
}
use (FooCategory) {
Foo foo = new Foo()
foo.bar = ""
foo.bar
}
// override using metaClass
Foo.metaClass.getProperty { String pname ->
println "in getProperty"
}
Foo.metaClass.setProperty { String pname, Object pValue ->
println "in setProperty"
}
Foo foo = new Foo()
foo.bar = ""
foo.bar
outputs
in setter
in getter
in setProperty
in getProperty
And because the getProperty/setProperty call makes the dispatch (eventually) to the getter/setter, you can prevent the getter/setter from being called at all, like this
class Foo {
String bar
}
Foo.metaClass.getProperty { String pname ->
println "in getProperty"
}
Foo.metaClass.setProperty { String pname, Object pValue ->
println "in setProperty"
}
#Category(Foo)
class FooCategory {
String getBar() {
println "in getter"
}
void setBar(String bar) {
println "in setter"
}
}
use (FooCategory) {
Foo foo = new Foo()
foo.bar = "hi foo1"
foo.bar
}
outputs
in setProperty
in getProperty
I want to create small app. I will login with user and password, then display option to select. If select option, display alert corresspondingly. But I can't get event click item in list.
Here is code:
public class Midlet extends MIDlet implements CommandListener{
private Display display;
private SampleCavans myCanvas;
private TextField username;
private TextField password;
private Form form;
private Command cancel;
private Command login;
private Command mNextCommand;
private List service;
String[] stringElements = { "Check Mail", "Compose","Addresses","Options","Signout","Calculator"};
public Midlet() {
display=Display.getDisplay(this);
username=new TextField("Login ID", "", 10, TextField.ANY);
password=new TextField("Password", "", 10, TextField.PASSWORD);
cancel=new Command("Cancel", Command.CANCEL, 2);
login=new Command("Login", Command.OK, 2);
form=new Form("Sign in");
form.append(username);
form.append(password);
form.addCommand(cancel);
form.addCommand(login);
form.setCommandListener(this);//add event click for form
myCanvas=new SampleCavans();
}
public void startApp() {
display.setCurrent(form);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
notifyDestroyed();
}
public void menu()
{
//List service=new List("Choice one",Choice.EXCLUSIVE);
service=new List("Choice one",Choice.EXCLUSIVE,stringElements,null);
service.setCommandListener(this);
//service.addCommand(mNextCommand);
display.setCurrent(service);
}
public void tryAgain()
{
Alert error=new Alert("Login Incorrect","Please try again",null,AlertType.ERROR);
error.setTimeout(Alert.FOREVER);
username.setString("");
password.setString("");
display.setCurrent(error,form);
}
public void commandAction(Command c, Displayable d) {
String lable=c.getLabel();
if(lable.equals("Cancel"))
{
destroyApp(true);
}
else if(lable.equals("Login"))
{
validateUser(username.getString(),password.getString());
}
else if(c==List.SELECT_COMMAND)
{
int index = service.getSelectedIndex();
Alert alert = new Alert("Your selection",
"You chose " + service.getString(index) + ".",
null, AlertType.INFO);
Display.getDisplay(this).setCurrent(alert, service);
}
}
private void validateUser(String name, String pass) {
if(name.equals("12")&&pass.endsWith("12"))
{
menu();
}
else
tryAgain();
}
In midp a list is actually more like a menu with a selection of choices. You have to set a command on it, so that in your command action you can dispatch on this command, get the selection form the menu and set the next screen accordingly. Here's the code for something similar to what you are trying to do:
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class Login extends MIDlet implements CommandListener {
private static final String ONE = "One";
private static final String THE_OTHER = "The Other";
private Form form;
private Command cancel=new Command("Cancel", Command.CANCEL, 2);
private Command login=new Command("Login", Command.OK, 2);
private TextField username=new TextField("Login ID", "", 10, TextField.ANY);
private TextField password=new TextField("Password", "", 10, TextField.PASSWORD);
private List menu = new List("Menu", List.IMPLICIT, new String[] {"One", "The Other"}, null);
private Command selection=new Command("SELECTION", Command.ITEM, 1);
private TextBox message1= new TextBox("One", ONE, ONE.length(), TextField.UNEDITABLE);
private TextBox message2= new TextBox("The Other", THE_OTHER, THE_OTHER.length(), TextField.UNEDITABLE);
public Login() {
form=new Form("Sign in");
form.append(username);
form.append(password);
form.addCommand(cancel);
form.addCommand(login);
form.setCommandListener(this);
menu.setSelectCommand(selection);
menu.setCommandListener(this);
message1.addCommand(cancel);
message1.setCommandListener(this);
message2.addCommand(cancel);
message2.setCommandListener(this);
}
protected void destroyApp(boolean unconditional)
throws MIDletStateChangeException {
username.delete(0, username.size());
password.delete(0, password.size());
}
protected void pauseApp() { }
protected void startApp() throws MIDletStateChangeException {
Display.getDisplay(this).setCurrent(form);
}
public void commandAction(Command c, Displayable d) {
if(c == cancel) {
if(d == form) {
notifyDestroyed();
}
else {
Display.getDisplay(this).setCurrent(form);
}
}
if(c == login) {
char[] data1 = new char[10];
username.getChars(data1);
char[] data2 = new char[10];
password.getChars(data2);
if(loginOk(new String(data1), new String(data2))) {
Display.getDisplay(this).setCurrent(menu);
}
else {
notifyDestroyed();
}
}
if(c == selection) {
if(menu.getSelectedIndex() == 0) {
Display.getDisplay(this).setCurrent(message1);
}
if(menu.getSelectedIndex() == 1) {
Display.getDisplay(this).setCurrent(message2);
}
}
}
private boolean loginOk(String string, String string2) {
return true;
}
}
I am creating some forms and I need to create masks and validation for some fields.
Is it implemented in anyway in JavaFX?
My example of the mask.
Using:
<MaskField mask="+7(DDD)DDD-DDDD"/>
<MaskField mask="AA DDD AAA" placeholder="__ ### ___"/>
etc
Restricting input from Richard's fxexperience post:
TextField field = new TextField() {
#Override public void replaceText(int start, int end, String text) {
// If the replaced text would end up being invalid, then simply
// ignore this call!
if (!text.matches("[a-z]")) {
super.replaceText(start, end, text);
}
}
#Override public void replaceSelection(String text) {
if (!text.matches("[a-z]")) {
super.replaceSelection(text);
}
}
};
If you want to create your use a mask and create your own control, take a look at Richard's MoneyField, which also includes a sample project and source. Along the same lines there are controls to restict input to Integers, Doubles or formatted web colors (e.g. #rrggbb) in the fxexperience repository. All of these follow a common theme where they subclass Control, provide some properties to be get and set which define the public interface and then also define a private backing skin which handles rendering of the UI based on the values set through the public interface.
I had the same needs. I created this field, called it SpecialTextField, and pushed into GitHub. Example also there. Hope this help.
NOTE: this only works correctly with JRE 1.8.0_25 or lower. With JRE 1.8.0_48 or 0_51, the caret position is always set to 0 after each character input.
No, this is not implemented in standard JavaFX. You need to use some library or do it yourself.
This is my implementation of static mask for text fields. It works for date, phone and other types of static masks:
/**
* Adds a static mask to the specified text field.
* #param tf the text field.
* #param mask the mask to apply.
* Example of usage: addMask(txtDate, " / / ");
*/
public static void addMask(final TextField tf, final String mask) {
tf.setText(mask);
addTextLimiter(tf, mask.length());
tf.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
String value = stripMask(tf.getText(), mask);
tf.setText(merge(value, mask));
}
});
tf.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(final KeyEvent e) {
int caretPosition = tf.getCaretPosition();
if (caretPosition < mask.length()-1 && mask.charAt(caretPosition) != ' ' && e.getCode() != KeyCode.BACK_SPACE && e.getCode() != KeyCode.LEFT) {
tf.positionCaret(caretPosition + 1);
}
}
});
}
static String merge(final String value, final String mask) {
final StringBuilder sb = new StringBuilder(mask);
int k = 0;
for (int i = 0; i < mask.length(); i++) {
if (mask.charAt(i) == ' ' && k < value.length()) {
sb.setCharAt(i, value.charAt(k));
k++;
}
}
return sb.toString();
}
static String stripMask(String text, final String mask) {
final Set<String> maskChars = new HashSet<>();
for (int i = 0; i < mask.length(); i++) {
char c = mask.charAt(i);
if (c != ' ') {
maskChars.add(String.valueOf(c));
}
}
for (String c : maskChars) {
text = text.replace(c, "");
}
return text;
}
public static void addTextLimiter(final TextField tf, final int maxLength) {
tf.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
if (tf.getText().length() > maxLength) {
String s = tf.getText().substring(0, maxLength);
tf.setText(s);
}
}
});
}
See also:
JavaFX 2.2 TextField maxlength
Supported by current javafx-2 platform by default - No, but go through this link , it has many insights and sample code for Form validation in javaFX
public class NumberTextField extends TextField {
private int maxLenght;
public NumberTextField(int maxLenght) {
super();
this.maxLenght = maxLenght;
}
#Override
public void replaceText(int start, int end, String text) {
if (validate(text)) {
super.replaceText(start, end, text);
}
}
#Override
public void replaceSelection(String text) {
if (validate(text)) {
super.replaceSelection(text);
}
}
private boolean validate(String text) {
if (this.getText() != null) {
}
boolean status = ("".equals(text) || text.matches("[0-9]"));
if (this.getText() == null) {
return status;
} else {
return (status && this.getText().length() < maxLenght);
}
}
}
In some cases I would validate the text property:
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldV);
});
Unlucky: textField.setText(oldV); will enter the same function again, testing unnecessarily if oldVal matches.
If the TextField becomes a value that doesn't matches before this listener is added to the TextField, enter a not matching new value will cause a loop!!!
To avoid this, it will be safer to write:
String acceptableValue = "0";
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldVal.matches("\\d+") ? oldV : acceptableValue);
});
I wrote a class that extends the TextField and apply the mask.
package com.model;
import java.text.NumberFormat;
import java.util.Locale;
/**
* ATENTION
* DO NOT FORGUET TO IMPORT IN FXML
* <?import com.view.TextFieldMoney?>
*
* */
import javafx.scene.control.TextField;
public class TextFieldMoney extends TextField {
private int maxlength;
private String valor = "";
public TextFieldMoney() {
this.maxlength = 11;
}
public void setMaxlength(int maxlength) {
this.maxlength = maxlength;
}
#Override
public void replaceText(int start, int end, String text) {
// Delete or backspace user input.
if (getText() == null || getText().equalsIgnoreCase("")) {
valor = "";
}
if (text.equals("")) {
super.replaceText(start, end, text);
} else{
text = text.replaceAll("[^0-9]", "");
valor += text;
super.replaceText(start, end, text);
if (!valor.equalsIgnoreCase(""))
setText(formata(valor));
}
}
#Override
public void replaceSelection(String text) {
// Delete or backspace user input.
if (text.equals("")) {
super.replaceSelection(text);
} else if (getText().length() < maxlength) {
// Add characters, but don't exceed maxlength.
// text = MascaraFinanceira.show(text);
if (text.length() > maxlength - getText().length()) {
// text = MascaraFinanceira.show(text);
text = text.substring(0, maxlength - getText().length());
}
super.replaceSelection(text);
}
}
/*
*Return the number without money mask
**/
public String getCleanValue(){
String cleanString = getText().replaceAll("[^0-9]", "");
Double cleanNumber = new Double(cleanString);
return String.valueOf(cleanNumber/100);
}
private String formata(Double valor) {
Locale locale = new Locale("pt", "BR");
NumberFormat nf = NumberFormat.getInstance(locale);
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
return nf.format(valor);
}
public String formata(String valor) {
double v = new Double(valor);
return formata(v/100);
}
}
And in the FXML where is
<TextField fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />
put
<TextFieldMoney fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />
I want to show the virtual keyboard when the user is editing the textfield. I take this approach :
public class ChpModif extends TextField {
public ChpModif(int maxChars, FocusListener focusListener, DataChangedListener dataChangeListener, VirtualKeyboard vkb)
{
super();
setReplaceMenu(false);
if (maxChars != -1)
setMaxSize(maxChars);
addFocusListener(focusListener);
addDataChangeListener(dataChangeListener);
if (vkb != null)
VirtualKeyboard.bindVirtualKeyboard(this, vkb);
}
protected Command installCommands(Command clear, Command t9)
{
return null;
}
}
public class ModifierFicheClient extends Ecran implements ActionListener, DataChangedListener, FocusListener
{
private VirtualKeyboard vkNombre = new VirtualKeyboard();
private String textFieldStatus, listBoxStatus;
private ListBox genretxt;
private boolean modifFromUpdate;
private ChpModif nomtxt,prenomtxt,cintxt,adressetxt/*,genretxt*/,lieutxt,professiontxt,courieltxt,teltxt,datenaisstxt;
private Component cursorItem;
...
public ModifierFicheClient(SmartPhoneBanking controller,String prosp_id,int recordStoreID,Form prevForm)
{
super("");
vkNombre.setInputModeOrder(new String[]{VirtualKeyboard.NUMBERS_SYMBOLS_MODE});
...
modifFromUpdate = false;
cintxt = new ChpModif(12, this, this, vkNombre);
...
}
public void dataChanged(int type, int index) {
textFieldStatus = "CHANGED";
if (!modifFromUpdate)
{
try
{
if (type == DataChangedListener.ADDED || type == DataChangedListener.CHANGED || type == DataChangedListener.REMOVED)
{
if (Display.getInstance().isVirtualKeyboardShowingSupported())
{
if (!Display.getInstance().isVirtualKeyboardShowing())
cursorItem.pointerReleased(cursorItem.getAbsoluteX(), cursorItem.getAbsoluteY());
}
}
}
catch (ClassCastException cce)
{}
}
}
public void focusGained(Component chp) {
cursorItem = chp;
}
public void focusLost(Component arg0) {
}
protected void onShowCompleted()
{
...
update();
}
public void update()
{
modifFromUpdate = true;
cintxt.setText(fichesignalitique.elementAt(0).toString());
...
modifFromUpdate = false;
}
...
}
The problem is that at the first time when I edit the textfield then the virtualkeyboard is shown ; then I click the Ok button of the virtualkeyboard , and then I edit again the textfield. But in this time the virtualkeyboard is not shown !
So how to make the virtualkeyboard shown everytime I edit the textfield ?
Its entirely possible that this is a 1.4 bug that was fixed in 1.5 since I can't see it right now. The VKB was brand new in 1.4 .
Why the program is failed to run after I appended the checkbox's index.
agreeIndex = mainForm.append(agree);
import javax.microedition.midlet.*;
import java.util.*;
import javax.microedition.lcdui.*;
public class MainPage extends MIDlet implements CommandListener, ItemStateListener{
Ticker header;
Display display;
Form mainForm;
TextField name, num, phone, email, age;
ChoiceGroup gender;
private int choiceGroupIndex;
Command nextCom, clearCom, exitCom;
Page1 p1;
ChoiceGroup agree = new ChoiceGroup("Please read the terms and conditions from menu."
, Choice.MULTIPLE);
int agreeIndex;
public MainPage(){
header = new Ticker("**ABC Restraurant**Customer Survey**");
mainForm = new Form("Personal Information");
name = new TextField("User name: ", "", 20, TextField.ANY);
num = new TextField("User id: ", "", 10, TextField.NUMERIC);
phone = new TextField("Phone no.: ", "", 10, TextField.PHONENUMBER);
email = new TextField("E-mail: ", "", 20, TextField.ANY);
age = new TextField("Age: ", "", 3, TextField.NUMERIC);
gender = new ChoiceGroup("Gender: ", Choice.EXCLUSIVE);
nextCom = new Command("Next", Command.SCREEN, 1);
clearCom = new Command("Clear", Command.SCREEN, 2);
exitCom = new Command("Exit", Command.EXIT, 3);
p1 = new Page1(this);
mainForm.setTicker(header);
mainForm.append(name);
mainForm.append(num);
gender.append("Male", null);
gender.append("Female", null);
choiceGroupIndex = mainForm.append(gender);
mainForm.append(age);
mainForm.append(phone);
mainForm.append(email);
//agree.append("I agree with the terms and conditions.", null);
mainForm.append(agree);
mainForm.addCommand(nextCom);
mainForm.addCommand(clearCom);
mainForm.addCommand(exitCom);
mainForm.setCommandListener(this);
}
public void commandAction(Command c, Displayable s) {
if (c == exitCom)
{
try {
destroyApp(false);
} catch (MIDletStateChangeException e) {
e.printStackTrace();
}
notifyDestroyed();
} else if (c == clearCom) {
resetTransferInformation();
} else if (c == nextCom) {
display.setCurrent(p1.list);
//System.out.print(agreeIndex);
}
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
display = Display.getDisplay(this);
display.setCurrent(mainForm);
agree.append("I agree with the terms and conditions.", null);
agreeIndex = mainForm.append(agree);
}
public void itemStateChanged(Item item)
{
}
public void resetTransferInformation() {
name.setString("");
num.setString("");
phone.setString("");
email.setString("");
age.setString("");
}
public void back() {
display.setCurrent(mainForm);
}
}
You try to append agree to mainForm twice. (in constructor and in startApp)
It's incorrect