How to stop user from generating more events? - java

I am developing a java swing desktop application. The dialog form has an ok and cancel button. When the user clicks ok button the application does some processing. How can I stop user from clicking ok again before the event on ok button has finished executing. Also, i dont want the user to able to press the cancel button till ok has finished executed. Any help will be highly appreciated.

Enablement management is an integral part of UI logic. Action helps you doing so:
Action action = new AbstractAction("myAction") {
public void actionPerformed(ActionEvent e) {
setEnabled(false);
doPerform();
setEnabled(true);
}
};
button.setAction(action);
Beware: long running task must not be executed on the EDT, so this is for short-term only, to prevent the second or so click having an effect
Edit
just noticed that you tagged the question with jsr296, then it's even easier: you can tag a method of your presentation model as #Action and bind its enabled property to a property of the model
#Action (enabledProperty == "idle")
public void processOk() {
setIdle(false);
doStuff;
setIdle(true);
}
Plus there is support (much debated, but useable) for Tasks: basically SwingWorker with fine-grained beanified life-cycle support

If you want to disable all the controls, then I'd suggest using a GlassPane. See here for more info: http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html

The easiest way is to disable the button just after clicking it , and when the action performed is complete then re-enable it.

You can disable your button like yourButton.setEnabled(false); during your processing method and enable it again when it finishes.

It seems that what you want is something like a waiting cursor.

Related

How can I show a confirm dialog with Vaadin 23 when the user clicks on back button?

how can I show a dialog to stay or leave the current page with Vaadin 23, when a user clicks back button on browser?
Regards
It depends what you wish to achieve.
See this older discussion: Vaadin onbeforeunload event
Generally: use the onBeforeUnload javascript even for this
https://www.w3schools.com/tags/ev_onbeforeunload.asp
This is executed when the user would go away from your vaadin app, but not when using the back button inside your vaadin app.
For these you can use the navigation lifecycle events as documented here
https://vaadin.com/docs/latest/routing/lifecycle
Not sure if it also catches, when a user leaves your app...
Assuming you mean, that is it possible to prevent the navigation happening, you simply can't do that. If disabling back button is important for you, the only way is to enforce your users to use the application via desktop shortcut which starts the app using --app paramater (if using Chrome). This is not a limitation in Vaadin, but a general restriction in browser behavior.
There is already a possibility to handle Browser Back Button Event on Vaadin (https://vaadin.com/docs/v14/flow/routing/tutorial-routing-lifecycle):
public class SignupForm extends Div implements BeforeLeaveObserver {
#Override
public void beforeLeave(BeforeLeaveEvent event) {
if (this.hasChanges()) {
ContinueNavigationAction action = event.postpone();
ConfirmDialog.build("Are you sure you want"+
" to leave this page?")
.ifAccept(action::proceed)
.show();
}
}
private boolean hasChanges() {
// no-op implementation
return true;
}
}
This code works once but when you click on Cancel on Confirm Dialog so that you want to stay on current page and click again on Back Button on Browser, than you don't see any Confirm Dialog again... I can not understand, why...

How to trap the [x] in closing a Shell

I have the following Shell listener code
private class ShellListener extends ShellAdapter
{
#Override
public void shellClosed( ShellEvent e )
{
}
#Override
public void shellDeactivated( ShellEvent e )
{
}
}
I need to be able to trap when the Shell loses focus, ie: the user goes to another application. The shellDeactivated() does that. I also need to know when I explicitly close() the Shell. The shellClosed() does that.
However when a user clicks on the [x] icon at the top/right corner of the Shell, shellDeactivated() fires, then shellClosed() fires. I need to be able to ignore the shellDeactivated() when the [x] is clicked.
The ShellEvent does not have any pertinent information, it just holds the Shell object, not which Shell control initiated the event.
Is there any way I can trap for the [x] click?
Grumble grumble
Ok, inside shellClosed() I pop-up a message asking the user if they really want to quit. It seems that this is considered a lost focus event (true enough). That is what was firing the shellDeactivated() event.
So the shellClosed() fires, I show a pop-up message, which fires the shellDeactivated() event. And things happen out of order. A simple flag and back to normal :-)

Thread writting status update text on any components under mouse

This is a rather odd one. I am using a Swing button to launch a scan of a list of files. Because I want it to display updates on the status bar, I am using a Thread. Since Swing won't let anything draw until the button's code has finished, I am also using a Tread to allow me to change the 'Start Scan' button to a 'Stop Scan' button.
The problem is that if the wait cursor is placed over any other components, during the scan, the status messages are also being written onto those components, such as buttons (see sample button below code), check boxes, etc; which messes up the interface. Is this a major bug or is it not a good idea to do what I am doing? Is there a way around it?
private void jButton47ActionPerformed(java.awt.event.ActionEvent evt)
{
// Scan folders button.
//
this.getFrame().setCursor(new Cursor(Cursor.WAIT_CURSOR));
// If button is in stop mode then...
if (collection.isScanContinue())
{
collection.setScanContinue(false);
jButton47.setText(" Scan Folders For Files ");
jButton47.setBackground(view.getDefaultButtonCol());
}
else // in scan mode...
{
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
// Setup the stop scan process button (changes the scan button to a stop button).
//
collection.setScanContinue(true);
jButton47.setText(" Stop Scanning Folders ");
jButton47.setBackground(collection.getPrefs().getDeleteCol());
collection.scanSourceAndTargetFolders();
if(collection.isScanContinue())
{
// do scan
}
// Reset the stop scan button and flag.
//
collection.setScanContinue(false);
jButton47.setText(" Scan Folders For Files ");
jButton47.setToolTipText("Scans Source and, if required, Target folders.");
jButton47.setBackground(view.getDefaultButtonCol());
view.getFrame().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
t.start();
}
}
It cleans up fine if I re-validate the main frame, but it looks terrible during the file scan.
Any action involving swing, such as changing button text etc, should be performed on event dispatch thread using SwingUtilities.invokeLater. Otherwise, you'll run into concurrency issues like you see here. See this question for more details about how event thread works: Java Event-Dispatching Thread explanation
Also, for doing background tasks like this, Swing provides a handy utility called SwingWorker: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

Prevent JavaFX dialog from closing

I'm currently creating a dialog using JavaFX. The Dialog it self works very well but now I'm trying to add an input validation which warns the user when he forgets to fill out a text field.
And here comes my question: Is it possible to prevent the dialog from closing inside the Result Converter? Like this:
ButtonType buttonTypeOk = new ButtonType("Okay", ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().add(buttonTypeOk);
dialog.setResultConverter((ButtonType param) -> {
if (valid()) {
return ...
} else {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setHeaderText("Pleas fill all fields!");
alert.showAndWait();
//prevent dialog from closing
}
});
I noticed that the dialog dosn't close if an error was thrown inside the resault converter but this doesn't seems to be a good way to solve this problem.
If it isn't possible to solve the problem this way I could disable the button as described in this post. But I would prefer to keep the button enabled and display a message.
Thank you in advance !
How you are supposed to manage data validation in a dialog is actually explained in the Javadoc, I quote:
Dialog Validation / Intercepting Button Actions
In some circumstances it is desirable to prevent a dialog from closing
until some aspect of the dialog becomes internally consistent (e.g. a
form inside the dialog has all fields in a valid state). To do this,
users of the dialogs API should become familiar with the
DialogPane.lookupButton(ButtonType) method. By passing in a ButtonType
(that has already been set in the button types list), users will be
returned a Node that is typically of type Button (but this depends on
if the DialogPane.createButton(ButtonType) method has been
overridden). With this button, users may add an event filter that is
called before the button does its usual event handling, and as such
users may prevent the event handling by consuming the event. Here's a
simplified example:
final Button btOk = (Button) dlg.getDialogPane().lookupButton(ButtonType.OK);
btOk.addEventFilter(
ActionEvent.ACTION,
event -> {
// Check whether some conditions are fulfilled
if (!validateAndStore()) {
// The conditions are not fulfilled so we consume the event
// to prevent the dialog to close
event.consume();
}
}
);
In other words, you are supposed to add an event filter to your button to consume the event in case the requirements are not fulfilled which will prevent the dialog to be closed.
More details here
One other way to solve this is by using setOnCloseRequest if you don't want to relay only on the user clicking the "Okay" button. The event handler will be called when there is an external request to close the Dialog. Then the event handler can prevent dialog closing by consuming the received event.
setOnCloseRequest(e ->{
if(!valid()) {
e.consume();
}
});

In GWT, how to reset the URL when the user hits "Cancel" in the navigation confirmation dialog?

In my GWT application, I want to ask a user confirmation when he navigates out of the current application, i.e. by entering a URL or closing the browser. This is typically done by registering a ClosingHandler and setting the desired dialog message in the onWindowClosing method. This seems to work well.
However, if the user tries to navigate say to http://www.gmail.com (by typing it in the URL bar) and hits Cancel to indicate he doesn't want to navigate, then my app keeps running but the browser's URL bar keeps indicating http://www.gmail.com. This causes a number of problems later in my application and will give the wrong result if the user bookmarks the page.
Is there a way to automatically reset the URL when the user presses Cancel?
Or, alternatively, is there a way to detect the user pressed the Cancel button? If so, is there a way to set the URL without triggering a ValueChangeEvent? (I could add some logic to prevent this, but I'd rather use a built-in mechanism if it exists.)
Not sure if this works but did you try: History.newItem(History.getToken(), false); to reset the URL? It does set the history token without triggering a new history item.
I managed to do this. It looks like GWT DeferredCommand are executed after the confirmation window has been closed. This, combined with Hilbrand's answer above, give me exactly what I want. Here is exactly what I do:
public final void onWindowClosing(Window.ClosingEvent event) {
event.setMessage(onLeaveQuestion);
DeferredCommand.addCommand( new Command() {
public void execute() {
Window.Location.replace(currentLocation);
}
});
}
Where currentLocation is obtained by calling Window.Location.getHref() every time the history token changes.
I solved this by creating a custom PlaceController and replacing the token in the url. Not an ideal solution but it works!
if (warning == null || Window.confirm(warning)) {
where = newPlace;
eventBus.fireEvent(new PlaceChangeEvent(newPlace));
currentToken = History.getToken();
} else {
// update the url when user clicks cancel in confirm popup.
History.replaceItem(currentToken, false);
}

Categories