JavaFX confusing event handling on System Exit - javafx

The code bellow generates an Alert Dialog with two buttons, Ok and Cancel; and it also works as expected: if I click Ok, the system exits, otherwise the dialogs vanishes.
The strange thing is: if I ommit the else block handling the event, the platform will always exit, not considering the button I clicked.
Is that really the expected behaviour? Am I missing something?
private void setCloseBehavior()
{
stage.setOnCloseRequest((WindowEvent we) ->
{
Alert a = new Alert(Alert.AlertType.CONFIRMATION);
a.setTitle("Confirmation");
a.setHeaderText("Do you really want to leave?");
a.showAndWait().ifPresent(response -> {
if (response == ButtonType.OK) {
Platform.exit();
} else {
we.consume();
}
});
});
}

Here is the documentation for windows.onCloseRequest:
Called when there is an external request to close this Window. The installed event handler can prevent window closing by consuming the received event.
So, if you don't consume the close request event in the close request handler, the default behavior will occur (the window will be closed).
You don't really need to invoke Platform.exit() in the close request handler because the default behavior is to exit, so you could simplify your logic. You only need to consume the close request event if the user does not confirm that they want to close:
stage.setOnCloseRequest((WindowEvent we) ->
{
Alert a = new Alert(Alert.AlertType.CONFIRMATION);
a.setTitle("Confirmation");
a.setHeaderText("Do you really want to leave?");
Optional<ButtonType> closeResponse = alert.showAndWait();
if (!ButtonType.OK.equals(closeResponse.get())) {
we.consume();
}
});
There is a similar fully executable sample in the answer to the related StackOverflow question:
How can I fire internal close request?.

Related

What is gluon Alert generic type?

I went through some documentations here and here and found that gluon dialogs Can* have a generic type which will be the generic type of the object to be returned when you call showAndWait(). But gluon alerts (com.gluonhq.charm.glisten.control.Alert which is a subclass of com.gluonhq.charm.glisten.control.Dialog) does not seem to have a generic type and does not also seem to allow you to give it a generic type.
The problem occured when I tried to call setOnHidden as:
boolean shown;
String report = "";
Alert al = new Alert(AlertType.ERROR);
al.setContentText(report);
al.setAutoHide(false);
al.setOnHidden(e->{
shown = false;
});
shown = true;
al.showAndWait();
and I got the following warning on the setOnHidden() Call:
The method setOnHidden(EventHandler) belongs to the raw type Dialog. References to generic type Dialog should be parameterized
Any clarifications about gluon dialogs or ways to get rid of the warning are most welcome.
Like in the built-in JavaFX Alert control, the implicit type of the Gluon's Alert control is the same: the JavaFX built-in ButtonType, so if you click the OK button, it will return ButtonType.OK.
As you can see at the Alert JavaDoc, the control has one or two default buttons: an OK button for all of them, and a Cancel button for the Confirmation alert. Each of these buttons has as default result ButtonType.OK and ButtonType.CANCEL.
So this works for both Alert controls:
alert.showAndWait().ifPresent(result -> {
if (result == ButtonType.OK) {
// do something;
}
});
One of the things you will notice with both OK and Cancel buttons: the alert will be dismissed, so you don't have to do it.
You can also provide your custom buttons. Then you'll need to take care of calling hide():
final Button myYesButton = new Button("Yes");
myYesButton.setOnAction(event -> {
alert.setResult(ButtonType.YES);
alert.hide();
});
alert.getButtons().add(myYesButton);
About the setOnHidden, see Javadoc. It requires a LifecycleEvent:
alert.setOnHidden((LifecycleEvent event) -> System.out.println("alert hidden"));
but you can use just:
alert.setOnHidden(event -> System.out.println("alert hidden"));
Finally, make sure you are importing the right control:
import com.gluonhq.charm.glisten.control.Alert;
...
Alert alert = new Alert(javafx.scene.control.Alert.AlertType.ERROR);

JavaFX 8: Intercepting appication "exit"

In order to verify that all changes made by the user have been saved I want to intercept the exiting/quitting of a JavaFX application.
Is there a common way-to-go to achieve this like overriding an event or is there more to it?
As they have already said, this is done by intercepting WindowEvent.WINDOW_CLOSE_REQUEST. You can then stop the suspension by calling event.consume().
This is an example of how to capture the event and display a confirmation dialog. Depending on the user's choice, you can take serialization actions if you wish.
primaryStage.setOnCloseRequest(event -> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.initOwner(primaryStage);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setHeaderText("Exit");
alert.setContentText("Do you want to exit?");
alert.getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.NO);
Optional<ButtonType> optional = alert.showAndWait();
if(optional.isPresent() && optional.get() == ButtonType.OK) {
// save data
return;
}
event.consume();
});
In order for the implementation to be complete, you need to implement a logic for clear exit from the application from control. For example, when choosing from the File menu -> Close. When capturing the event, you must run WindowEvent.WINDOW_CLOSE_REQUEST to trick the exit logic.
closeMenuItem.setOnAction(event -> {
Window window = menuBar.getScene().getWindow();
window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
});
In the class Application there is the stop method which you can override possibly.

Docusign - Another ways to retrieve file

Is there another solutions rather than pass the returnUrl parameter. For example, retrieve the file directly in my server.
I have an iframe in a popup with the signature process. When I click on "Completed", the program launch my return url on iframe. But, I don't want that. I would prefer to close the popup and so to detect that the button "Completed" was clicked and the URL changed.
I have this code for detecting location change but got this error : "Origin cross platform".
window.FinishSignatureProcess = function (event, e)
{
try {
var source = e.contentWindow.location.hash; //Line problem
}
catch (e) {
//Exception
}
}
You can use the Docusign GetEnvelopeDocument API to retrieve the bytes of the document
I found a solution for my problem.
I simply redirected to a page indicating that it's finished and it's up to the user to close the popin.

Activity Indicator is not visible on xaml page in xamarin.forms?

I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.

FileReference.download() not working

I'm building a Flex app which requires me to download files.
I have the following code:
public function execute(event:CairngormEvent) : void
{
var evt:StemDownloadEvent = event as StemDownloadEvent;
var req:URLRequest = new URLRequest(evt.data.file_path);
var localRef:FileReference = new FileReference();
localRef.addEventListener(Event.OPEN, _open);
localRef.addEventListener(ProgressEvent.PROGRESS, _progress);
localRef.addEventListener(Event.COMPLETE, _complete);
localRef.addEventListener(Event.CANCEL, _cancel);
localRef.addEventListener(Event.SELECT, _select);
localRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityError);
localRef.addEventListener(IOErrorEvent.IO_ERROR, _ioError);
try {
localRef.download(req);
} catch (e:Error) {
SoundRoom.logger.log(e);
}
}
As you can see, I hooked up every possible event listener as well.
When this executes, I get the browse window, and am able to select a location, and click save. After that, nothing happens.
I have each event handler hooked up to my logger, and not a single one is being called! Is there something missing here?
The problem seems to be with my command being destroyed before this could finish.
For a proof of concept, I set my localRef variable to be static instead of an instance variable, and everything went through successfully! I guess Cairngorm commands kill themselves asap!

Resources