We're using the Wicket Wizard component. On the last step of the wizard, we find that if the user clicks the finish button rapidly, then Wicket calls our onFinish() method multiple times. This causes problems for us.
Interestingly, the problem occurs in all browsers we've tried (IE, Chrome), but not in Firefox. This browser appears to detect the multiple clicks, and only sends one click event to the server.
Question is, what can we do to prevent this?
From looking at the Wicket framework code, I can see that the nav buttons are contained in a WizardButtonBar, and the FinishButton is handling the onClick event, but I'm unsure of the correct way to override or control this behaviour, and somehow detect the multiple onClick events
You don't seem to use Ajax, do you?
If you did, you could just add a veil - e.g. by overriding #getAjaxIndicatorMarkupId() - and any double submit would be prevented. Additional benefit: If the user pressed the back button after the wizard has finished, the browser will leave the wizard and the user cannot finish it a second time.
For non-Ajax request, you'll have to add your own veil JavaScript to your button.
To prevent the user from going back and finishing the wizard a second time, you can use a token-base solution:
On start of the wizard aquire a token (could just be a counter). Once the wizard has finished, mark the token as expended (e.g. store it along your domain objects).
On each request to the wizard, you can check whether the token is still valid - if not, redirect the user to another page explaning that the wizard has already finished.
Andrew very kindly submitted the original question for me. I did try doing this (pretty much as you suggested):
class MyWizard extends Wizard {
private Integer finishPressed = -1; // deliberately set an invalid value to start with
public MyWizard() {
finishPressed = 0; // only place where finishedPressed is set to 0
log.info( "init: finishPressed={}", finishPressed );
}
#Override
public void onFinish() {
log.info( "begin: finishPressed={}", finishPressed );
if ( ! finishPressed ) {
finishPressed += 1;
// do onFinish actions ...
}
log.info( "end: finishPressed={}", finishPressed );
}
}
However, what I find is that onFinish() is called as many times as I pressed the Finish button, but each time finishPressed is 0 when it enters the method, instead of the count incrementing.
Note: I only ever see "init: finishPressed=0" once in the log. I don't know how it keeps getting reset to 0. However, I did notice that the onFinish() calls were handled by a different thread each time. But as said, the constructor (the only place finishPressed is set to 0) was only called once.
Only by declaring finishPressed as static (which obviously will cause problems in real live operation) do I see the finishPressed incrementing as expected.
Related
Following situation:
I code a Domino game for Android. At the beginning of the game, if not a bot is the starting player, a user should pick two Dominos that get onto the board.
Overview of my non-working approach:
Definition of an empty ArrayList, call of a function that attaches Click Listeners on every Domino belong to the user followed by a while loop that does nothing, should just be the mechanism to wait until the user has picked two dominos. These dominos should be stored in the ArrayList(adding of the dominos to the ArrayList in FirstDominosPickerListener)
The code
In the activity:
ArrayList<Domino> starterDominos = new ArrayList<Domino>();
startingPlayer.chooseStartDominos(starterDominos);
the function:
public void chooseStartDominos(ArrayList<Domino> starterDominos){
///Every Domino gets a ClickListener
for (Domino domino : playerSet){
domino.setOnClickListener(new FirstDominosPickerListener( starterDominos));
}
//The idea is to wait until the user has picked two Dominos. With that loop, no UI at all shows up
while (starterDominos.size()<2){
Log.v(LOG_TAG," WAIT!!!!");
}
}
The problem is the while Loop. With the loop, no UI shows up, i get an empty white screen, altough the code runs. In logcat, i get infinite "Wait" messages. No idea why.
A second approach I've tried was to call a Timer task in the activity after that checks if two dominos were picked (through the size of the list) starterDominos = startingPlayer.chooseStartDominos(starterDominos);
I realized that couldn't work because that runs in another thread and because of that, it wasn't possible to access any part of the UI. But the mechanism to pick the dominos worked. UI showed up and run() ended after two dominos were picked through cancel().
So why does the while loop leads to that behavior? Is the whole approach wrong and if so what can I do that the app waits until the dominos were picked and then proceed
Your while loop is blocking the main UI thread so nothing can be drawn or updated on the screen. You need to set up a listener for when a user selects a domino, then proceed after a user has selected two dominos.
You can use a class variable in the activity class 'userDominoSelectCount' which can be a short integer field initialized to 0.
You can add the onClickListener for domino in the activity onCreate method itself:
domino.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
++userDominoSelectCount;
if(userDominoSelectCount == 2){
//initiate AI logic
userDominoSelectCount = 0;
}
}
});
The way you are doing will block the main thread as mentioned in other answer to the question. OnClicklisteners are meant to be run in event loop and ideally should not block UI.
In my application, i have a radio button field selected. When i am opening the page, the selected field has some delay. Example: I am opening the page, that radio button is in unselected state, after some time (say like hovering on the screen/scrolling) the radio button turns to selected state. Is there is any other way to solve this delay?
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
statementGroupSelectionModel.setSelected(item, profile.getSelected());
}
});
Here in the above code, "item" is widget field name and depending upon my "getselected" value, the radio icon will get selected. Here my "getSelected" value is true.
Any code inside scheduleDeferred will have its execution postponed until the browser finishes rendering the page and the flow control returns to the Javascript event loop, as explained in GWT's documentation:
Deferring some logic into the immediate future: the Scheduler class
Sometimes you want to break up your logic loop so that the JavaScript event loop gets a chance to run between two pieces of code. The Scheduler class will allow you to do that. The logic that you pass to Scheduler will run at some point in the future, after control has been returned to the JavaScript event loop. This little delay may give the interface a chance to process some user events or initialize other code. To use the Scheduler class in its simplest form, you create a subclass of the Command class, overriding the execute() method and pass it to Scheduler.scheduleDeferred
If what you want is for the radio button to be selected immediately, just remove the Scheduler wrapping, i.e. move statementGroupSelectionModel.setSelected(item, profile.getSelected()); out of scheduleDeferred.
// Put this here
statementGroupSelectionModel.setSelected(item, profile.getSelected());
// Remove the following code
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
...
});
If what you want is not that (sorry, your explanation is rather unclear), but just to be able to set the delay time yourself instead of having to wait for the browser, you can use the Timer class which is explained in the documentation linked above.
My game takes around a minute to load in android till the first screen appears. Till the time its loading, jmonkey’s input manager seems to queue all inputs which results in nasty behavior(automatic button clicks) as soon as my first nifty screen loads.
Same happens when the scene loads(which again takes a while on pressing the appropriate nifty button). This happens despite the fact that I set mappings and listeners in the last App State which loads.
Is there a way to flush all previous input which I can call just before and after adding listeners to input manager?
I dont do much work in update() and initialize of my appstates but some functions (reinitialize()) which I call on nifty's OnClick(), loads all the scene and models in the scene garph so it takes a while. Here is a pseudo code of my application
In Main.java {
// Nothing in SimpleUpdate()
// This app state contains
stateManager.attach(new MainMenuAppState());
}
In MainMenuAppState.java implements ScreenController {
initialize() {
niftyDisplay = new NiftyJmeDisplay(app.getAssetManager(), app.getInputManager(), app.getAudioRenderer(), app.getGuiViewPort());
// Create a new nifty GUI object
nifty = niftyDisplay.getNifty();
// attach a couple of more app states which also has nothing significant in update loop
// do some good computation
// attach 5 new APP STATES which does not have anything significant in update()
display the appropriate screen of nifty
}
onClick() {
nifty.gotoScreen(“loadScreen”);
// appstate previously attached. they dont have anything significant in update.
// They have significant initialize methods.
app.enqueue(
rgas.reInitialize(time,cameraLoc,cameraRot);
maes.reInitialize(qId); // loads all the scene and models on screen
nifty.gotoScreen(“hudScreen”);
nifty.getScreen(“hudScreen”).findElementByName(“ConfirmModuleButton”).setFocus();
ppes.reInitialize(); // this contains input mappings
);
}
}
If there is a way to do this it will be on the InputManager so you could check out the API for that. Your problem may be though that the queue isn't really a queue in the way you are thinking. Potentially it is not a queue of input events but a queue of actions being taken in response to the events. Since events don't process until the update loop runs them then if the upload loop is stalled they will keep building up.
You could simply not add the listeners until the application has finished loading, then any events will get ignored automatically. You could also try breaking the scene loading up using a queue or similar of your own to load things a bit at a time while not completely stalling the system.
You may get a better response on this question if you try the jME3 forums. There are more monkeys active there than here including people with more detailed knowledge of the input system than me :)
I guess what Tim B said is your best bet.
However you could try calling nifty.setIgnoreMouseEvents(true) and nifty.setIgnoreKeyboardEvents(true) at some appropriate time to shut-off handling of any events that might reach Nifty and enable it later again.
I've got a button that kicks off a background thread to do some work and I am trying to use a ProgressDialog to prevent the user from double clicking that button (or any other ui elements) while that work is being done. The first thing I do in my buttons onClick code is to display the progress dialog, which takes over the screen. The problem I am seeing is that if I rapidly tap this button, sometimes two or more presses will register before the ProgressDialog is shown. This leads me to assume that ProgressDialog.show() is returning before the ProgressDialog is actually visible.
Can anybody confirm this? Also, is there a way to change this behavior, or at least get a notification of when the dialog is actually visible? I saw Dialog.onStart() but given the javadoc, this appears to be called before the Dialog is actually visible...
UPDATE:
While it appears that there is no good way of solving this problem in general, the following works for my situation where my work is done by an external thread and the amount of work to do takes longer than the time it takes for all the button clicks to be processed:
void myOnClickHandler() {
if(myButton.isEnabled()) {
myButton.setEnabled(False);
// do work here
// setEnabled(true) is invoked at the end of my spawned thread's run().
}
}
No.
The problem is you clicked many times before the click event is delivered. (i.e. it is queued before you run ProgressDialog.show().)
From what I've noticed in Android you can double click on a button rapidly and have the onClick listener fire twice (or even more) regardless of the code in the listener (even if you disable the button immediately).
I reported a bug a while ago here: http://code.google.com/p/android/issues/detail?id=20073 but of course these things tend to go "unnoticed" by Google. Feel free to star it in hopes of getting Google's attention
in echo 3 i have a problem setting focus on a specific text field in a new screen. The probelm occurs when a user holds their mouse on the reference button on the previous screen as opposed to just a simple click.
it looks similar to this:
public void display screen {
build window
if window isnt null{
build screen
if screen.textfield isnt null{
Thread t {
thread sleep 10000
screen.textfield.setFocus
}
}
}
}
in the pseudo above the focus would be set if the user user held the reference button down on the screen before for less than 10 seconds, in which case the focus would not be set until the remaining thread time passed. this isnt good because it take too long; and lower wait delay doesnt insure that the focus will set at all because the user might hold the key for longer.
I have tried launching multiple threads and using timers to hammer the focus in but that didnt work... is there something im missing about how the code is built internally because it seems that the whole thing is built despite the fact that the user hasnt let go of the button.
If thats the case is there a way to do it on release?
Thank You
Found a solution. The problem was with using IE6. I presume the order in which it builds is different to that of IE7+.