I am creating 2-3 checkbox field in my screen and adding those in a vertical field manager. Idea here is to disable other check box on click of another checkbox. but it is giving me stackoverflow error. I am posting my code here...
final CheckboxField[] checkBoxField = new CheckboxField[2];
checkBoxField[0] = cashCardCheckboxField;
checkBoxField[1] = creditDebitCardCheckboxField;
checkBoxField[0].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[0].getChecked()){
checkBoxField[0].setChecked(false);
}else{
checkBoxField[0].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[0].setChecked(false);
}
}
});
checkBoxField[1].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[1].getChecked()){
checkBoxField[1].setChecked(false);
}else{
checkBoxField[1].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[1].setChecked(false);
}
}
});
Thanks and Regards.
Solution
Try using this code. It allows you to create any number of checkboxes. When one is checked, the listener will uncheck all the other ones.
public class CheckBoxScreen extends MainScreen {
private CheckboxField checkBoxField[];
public CheckBoxScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
checkBoxField = new CheckboxField[3];
checkBoxField[0] = new CheckboxField("one", true); // checked by default
checkBoxField[1] = new CheckboxField("two", false);
checkBoxField[2] = new CheckboxField("three", false);
FieldChangeListener listener = new CheckboxListener();
for (int i = 0; i < checkBoxField.length; i++) {
checkBoxField[i].setChangeListener(listener);
add(checkBoxField[i]);
}
}
private class CheckboxListener implements FieldChangeListener {
public void fieldChanged(Field field, int context) {
if (context != FieldChangeListener.PROGRAMMATIC) {
// user modified this field
CheckboxField checkbox = (CheckboxField)field;
if (checkbox.getChecked()) {
// uncheck the other checkboxes
for (int i = 0; i < checkBoxField.length; i++) {
if (checkBoxField[i] != checkbox && checkBoxField[i].getChecked()) {
checkBoxField[i].setChecked(false);
}
}
}
} else {
// nothing more to do here ... this time, fieldChanged() is being
// called as a result of calling setChecked() in the code.
}
}
}
}
Why Your Code Created a Stack Overflow
The fieldChanged() method gets called whenever a field has its properties modified. For a CheckboxField, that happens when the field is checked or unchecked. This can happen either because the user checks/unchecks the field, or because your code calls setChecked(boolean). This line:
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
is what allows the code inside fieldChanged() to determine if this call is occurring because the user changed the field, or because setChecked() was called by your code. Unfortunately, you have placed calls to setChecked() in all branches of the if statement, which causes setChecked() to be called both for user events, and when your code changes the fields.
In this code:
checkBoxField[0].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[0].getChecked()){
checkBoxField[0].setChecked(false);
}else{
checkBoxField[0].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[0].setChecked(false);
}
}
});
it is the last line (checkBoxField[0].setChecked(false);) that is causing problems. That else branch is reached after calling setChecked() in the "manually clicked" branch of the if statement. Once you call setChecked(false) again, you have modified the field programmatically. This will cause fieldChanged() to be called back again. And again. And again. This loop will never stop, until the program stack is full, and your app crashes.
So, if you see my code, you notice that I am not calling setChecked() in the programmatic branch of the if statement. Another problem in your code is that you don't have the correct logic to uncheck checkbox 1 when checkbox 0 is checked. But, that's only a functional bug. The recursive call to fieldChanged() is what caused the stack overflow.
Hope that helps.
Related
Getting this popup every time whenever calling a bean method via valueChangeListener property from SelectOneChoice in a jsff page.
I need help to block this unwanted popup.
SelectOneChoice's property of the .jsff page:
<af:selectOneChoice value="................."
label=".................."
required="..............."
shortDesc=".............."
id="....................."
valueChangeListener="#{TransferWorkAreaBean.onBookLovChange}"
autoSubmit="true">
<f:selectItems value="............" id="si2"/>
<f:validator binding="......."/>
</af:selectOneChoice>
Method in Bean Class::
public void onBookLovChange(ValueChangeEvent valueChangeEvent) {
valueChangeEvent.getComponent().processUpdates(FacesContext.getCurrentInstance());
invokeELMethod("#{bindings.methodToExecute.execute}", new Class[0], new Object[0]);
AdfFacesContext.getCurrentInstance().addPartialTarget(getBusinessTable());
}
Method details of binding Method::
public void executeInvetoryQueryOnBookChange(String btg) {
OAViewObjectImpl vo = getBusinessOverview();
VariableValueManager vvm = vo.ensureVariableManager();
vvm.setVariableValue("bindBookTypeCode", btg);
vo.executeQuery();
}
Please note, in some places I have used encrypted data for policy.
Please also note, that the uncommittedDataWarning property is not ENABLED.
This popup only appear when the option uncommittedDataWarning is set to "on" at the root af:document tag. Try to run a full search in your JDevelopper for "uncommittedDataWarning".
Another way of avoiding this popup in this specific case would be to ensure that your data are committed or rollback in your data model. As the popup only appear if some data aren't committed when a user navigate outside the af:document. You could run something like so right before your
invokeELMethod("#{bindings.methodToExecute.execute}", new Class[0], new Object[0]);
How to commit if needed (https://cedricleruth.com/how-to-programmatically-commit-or-rollback-a-transaction-in-oracle-adf/)
private void commitIfDirty() {
try {
ViewObject vo = this.getViewObjectFromIterator("YOUR_ITERATOR_NAME");
boolean isNotSaved = vo.getApplicationModule()
.getTransaction()
.isDirty();
if (isNotSaved) {
vo.getApplicationModule()
.getTransaction()
.validate();
vo.getApplicationModule()
.getTransaction()
.commit();
}
} catch (ValidationException validationException) {
//log it and warn the user that his data isn't valid
} catch (Exception error) {
//log it and warn the user something went wrong
}
}
private ViewObjectImpl getViewObjectFromIterator(String nomIterator) {
ViewObjectImpl returnVO = null;
DCBindingContainer dcb = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
if (dcb != null) {
DCIteratorBinding iter = dcb.findIteratorBinding(nomIterator);
if (iter != null) {
returnVO = (ViewObjectImpl)iter.getViewObject();
}
}
return returnVO;
}
I have an activity that shows the results of the previous activity to the user. I save these results to a database. In my onCreate method I create a reference to my ViewModel and populate a List.
mAtcViewModel = new AtcViewModel(getApplication());
atcUserStatsList = mAtcViewModel.getAllUsersList();
I then go on call the save to database method after this assignment:
private void saveToDB(String playerName) {
mUser = playerName;
getAtcUser getAtcUser = new getAtcUser(playerName, this);
getAtcUser.delegate = this;
getAtcUser.execute();
}
When I get the result from onPostExecute this method is called:
#Override
public void processFinish(AtcUserStats atc_user) {
callOnChanged(atc_user);
}
This then calls a method where I am able to see the users previous stored results and adjust them with their new results but in this block of code a problem only sometimes arises, saying that atcUserStatsList is null:
try {
for (int i = 0; i < atcUserStatsList.size(); i++) {
if (atcUserStatsList.get(i).getUserName().equals(mUser)) {
mAtcViewModel.updateAtcPlayerStats(mUser, finalDartsHit, finalGamesWon, finalGamesPlayed, finalSinglesPlayed, finalDoublesPlayed, finalTreblesPlayed, finalDartsThrown,
finalSinglesDartsThrown, finalDoublesDartsThrown, finalTreblesDartsThrown, finalSinglesDartsHit, finalDoublesDartsHit, finalTreblesDartsHit, finalSecondPlace, finalThirdPlace);
}
}
} catch (Execption e) {
e.printStackTrace();
Log.d("atcUserStatsList", "Unable to save to database");
getMessage("Unable to save to database");
}
When I debug the list is populated most of the time and then when I run the app without debugging sometimes it is empty/null and the snackbar message appears and nothing is saved whereas other times it wouldn't appear and results are saved? Why would this be?
Is it anything to do with the lifecycle?
EDIT:
For example here is the list populated while debugging now this code will work:
And tbh for some reason it can be hard to get this list not Null when debugging(?).
I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?
The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.
Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.
I have two classes , one called AdminMenu class where variable VoteCycle is a boolean variable that enables a voter to vote provided that the VoteCycle is enabled and another class called LogInMenu where I would like to utilize it.
I'm doing this for my school project.
The problem I have is that even if I select enable which is meant to change the boolean value to true , I'm still getting the false output.. If you don't understand what I mean, my code below should explain it.
Its very basic programming.
The Class
public class AdminMenu extends javax.swing.JFrame {
public boolean VoteCycle;
The method
private void VoteComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
if(vCycle.getSelectedItem().toString().equalsIgnoreCase("True"))
{
VoteCycle=true;
}
else if(vCycle.getSelectedItem().toString().equalsIgnoreCase("False"))
{
VoteCycle=false;
}
}
This is the class where I would like to use the variable to allow users to log in.
The class is called LogInMenu().
At the start of the class I created an object of the class where the variable was defined in using
AdminMenu AdminMenu=new AdminMenu();
DataValidation validate=new DataValidation();
ConnectDB db=new ConnectDB();
I will just post the relevant code for this class:
private void EnterBtnActionPerformed(java.awt.event.ActionEvent evt) {
if(AdminMenu.VoteCycle)
{
String Voter=voter.getText();
boolean detail = false;
if (validate.Verify(Voter))// Validates Data
{
try
{
detail = db.VoterLogIn(Voter);
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
if (detail)
{
new VoterMenu().setVisible(true);
this.dispose();
}
else
{
JOptionPane.showMessageDialog(null, "The Username or Password entered is incorrect");// error message
}
}
}
else
{
JOptionPane.showMessageDialog(null, "Voting is currently disabled", "Error", JOptionPane.ERROR_MESSAGE);
}
Even after selecting the combo box option to enabled, I return to the LogInMenu class
and if i attempt to login I receive the "Voting is currently disabled" error.
I would really appreciate any help offered , Thank you!
P.S : I'm unsure how to use a toggle button and allow its state to be kept when logging into the administrators menu or just how to use the toggle button at all.
So instead i'm using a combox box to set my variables values.
The problem I have is that even if I select enable which is meant to
change the boolean value to true , I'm still getting the false
output..
Because, the elements of your JComboBox vCycle are { "Disabled", "Enabled", " " } whereas, you are checking the selectedItem for true and false. You should compare the selected value of vCycle for Diabled or Enabled instead of true and false.
if(vCycle.getSelectedItem().toString().equalsIgnoreCase("Disabled"))
{
VoteCycle=true;
}
else if(vCycle.getSelectedItem().toString().equalsIgnoreCase("Enabled"))
{
VoteCycle=false;
}
}
Apart from checking for the wrong text value of True and False instead of Enabled and Disabled, your code doesn't handle the case where it's neither.
Change your code to the single line:
VoteCycle = vCycle.getSelectedItem().toString().equalsIgnoreCase("Enabled");
Not only is it less code, and more readable, it caters (one way or another) for the neither case.
Is there a way to disable the Back button in a browser (basically clearing the History token stack) in GWT? Once I browse to a certain page in my application I want to make sure that the user can't use the back button to go back, but only be able to use links on the page to navigate the site.
You cannot disable a button just intercept it and change its return to something the browser does not understand.
This removes the history:
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
event.setMessage("My program");
}
});
To understand it see: http://groups.google.com/group/google-web-toolkit/browse_thread/thread/8b2a7ddad5a47af8/154ec7934eb6be42?lnk=gst&q=disable+back+button#154ec7934eb6be42
However, I would recommend not doing this because your it goes against good UI practices. Instead you should figure out a way that the back button does not cause a problem with your code.
Call the method below in the onModuleLoad().
private void setupHistory() {
final String initToken = History.getToken();
if (initToken.length() == 0) {
History.newItem("main");
}
// Add history listener
HandlerRegistration historyHandlerRegistration = History.addValueChangeHandler(new ValueChangeHandler() {
#Override
public void onValueChange(ValueChangeEvent event) {
String token = event.getValue();
if (initToken.equals(token)) {
History.newItem(initToken);
}
}
});
// Now that we've setup our listener, fire the initial history state.
History.fireCurrentHistoryState();
Window.addWindowClosingHandler(new ClosingHandler() {
boolean reloading = false;
#Override
public void onWindowClosing(ClosingEvent event) {
if (!reloading) {
String userAgent = Window.Navigator.getUserAgent();
if (userAgent.contains("MSIE")) {
if (!Window.confirm("Do you really want to exit?")) {
reloading = true;
Window.Location.reload(); // For IE
}
}
else {
event.setMessage("My App"); // For other browser
}
}
}
});
}
I found a way to make GWT ignore the back-button: Just add historyitem x if no historyitem was set and do nothing on x.
set a historyitem on startup
History.newItem("x")
in the ValueChangeHandler of History add the following:
String historyToken = event.getValue();
if (!historyToken.equals("x"))
History.newItem("x");
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
event.setMessage("My program");
}
});
That is not a fool proof solution. In fire fox I can press the back button and the onWindowClosing method is never invoked. The reason is that I have used History.newItem() and since history exists the back button or backspace buttons simply navigate through the browser history.
So....fix that :)
Put this in your index.html file:
window.open('html page(For example trial.html)', 'Name of the desired site', width='whatever you want',height='whatever you want', centerscreen=yes, menubar=no,toolbar=no,location=no,
personalbar=no, directories=no,status=no, resizable=yes, dependent=no, titlebar=no,dialog=no');