JavaFX 8: Intercepting appication "exit" - javafx

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.

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);

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.

how to make an object visible again in game maker

Fist of all, I'm really sorry for my bad English and I pretty new to game maker .
I have 2 object in the game : obj_apple and obj_door( I unchecked visible box)
my question is
how can I make an obj_door visible in the room when all the obj_apple are destroyed?
Object obj_door, Step event, place code (Add event -> Step -> Step -> tab Control -> section Code, first icon (Execute code)):
if !instance_exists(obj_apple) visible = true;
Another option, so you aren't making a check in every step event, is to put the check for the number of obj_apple in the destroy event of obj_apple.
For example, in the destroy event of obj_apple you would have:
if (instance_number(object_index) == 0) {
with (obj_door) {
visible = true;
}
}

JavaFX confusing event handling on System Exit

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?.

WF4 Rehosted Designer OnActivityAdded Event?

I'm looking at rehosting the workflow designer. I want to be able to run some code whenever the user adds an activity to the designer canvass. Is there an event that fires when the user adds an activity at design time? Or is there an event on the activity that I can consume? Thanks!
For anyone who might stumble onto this, here's what I figured out...
First off, when creating the workflow designer, you need to subscribe to the ModelChanged event.
_workflowDesigner = new WorkflowDesigner();
_workflowDesigner.Load(new Sequence());
ModelService ms = _workflowDesigner.Context.Services.GetService<ModelService>();
if (ms != null)
ms.ModelChanged += new EventHandler<ModelChangedEventArgs>(ms_ModelChanged);
My event handler looks like this...
void ms_ModelChanged(object sender, ModelChangedEventArgs e)
{
if (e.ItemsAdded != null && e.ItemsAdded.Count<ModelItem>() == 1)
{
ModelItem item = e.ItemsAdded.FirstOrDefault<ModelItem>();
var test = item.GetCurrentValue() as MyActivityType;
if (test != null && test.Id == null)
{
//do whatever initialization logic is needed here
}
}
}
I need to give credit to this source for pointing me in the right direction.
One thing to be careful of - when you move an activity within the model, two events are raised, a remove and an add. At this point, I don't need to worry about whether I'm adding or moving an activity as I can tell whether it has been initialized, but if you need to know whether something has really been added to the model, you might need to track both events.

Resources