javafx 8 dialog and concurrency - concurrency

I want to show a custom JavaFX 8 dialog to a user, capture data from the user and then close the dialog after the data is saved to the database (or shows an error message\alert).
At the moment, the dialog is shown with the following code:
Optional<MyType> result = dialog.showAndWait();
Followed by code:
myrepository.save(result)
From reading the documentation, it looks like instead I should perform this repository.save in a background Task?
It looks like this code could only be executed after showAndWait(); and couldn't close the standard dialog as this would need to be done on the JavaFX application thread?
Is there a way to only show the dialog, save the data, and then show a confirmation dialog only if the database save succeeds on the background Task?

From reading the documentation, it looks like i should perform this repository.save in a background Task?
Yes, it is correct because database queries take time and we don't want our application to become unresponsive while the database query is executed. Running tasks on the background thread avoids it.
Is there a way to only close the dialog and show a confirmation dialog if the database save succeeds on the background Task?
You can use task's succeeded property to close the previous dialog and open a new one.
// If database query is successful
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
// Code to close the previous dialog
//Show confirmation dialog
}
});
Similarly, if the task fails you can use the failed property to update the dialog or show a new dialog.
// On fail
// Using Lambda
runFactoryTask.setOnFailed( t -> {
// Update
});
There is a very nice answer by James_D on using threads and database, I strongly recommend to go through it :
Using threads to make database requests

Related

QT C++ How to lock application or disable clickable for 3-5 minute

I want to disable click for whole application while receiving data from serial connection. I want to print information on the screen with a message box and turn off clicking for a certain time, how can I do it?
Grabbing mouse for widgets or setKeepMouseGrab for qml may be useful. Add a dummy widget which gets the mouse events. Make it grab the events when you start receiving data.
'Blocking' an application is never a good idea, because your OS will think the application unresponsive and shoot it down forcibly.
What you want, is a modal dialog (which runs on the main thread) with a progress indicator and no clickable interfaces.
A very basic code to achieve that would be:
void startTransfer()
{
ProgressBarDialog dlg; //Inherits from QDialog
//Create asynchronous transfer task.
dlg.setModal(true);
//Connect task and modal dialog
dlg.exec();
}
exec will 'block' all interaction with the other windows while the transfer is running. In fact, exec will only return, once the dialog is done with its job.

Prompt user to save changes when closing MFC view

I have an MFC MDI application, in which it is possible for documents to have multiple views, and for users to customise and then save layout data for the views. This data is associated with the views, not the documents.
I would like to prompt the users to save if they choose to close a view with unsaved layout changes, and am running into problems, as it seems MFC is only geared towards changes in the document. Here are some approaches I've tried:
Override CDocument::SaveModified function, which gets called by the framework when a document is closed. In this function, I send a message to all the document's views, which can then check for unsaved changes and prompt the user.
Perform the check inside the View's destructor.
Perform the check inside the View's OnClose handler
Each of these approaches has problems. (1) is the best, but it fails to deal with cases where there are several views onto one document, and the user closes one of the views. As the document is still open, SaveModified is not called.
The problem with (2) is that on application shutdown, the application has already disappeard by the time any CView destrutors are called. This can leave an orphan dialog box open on the desktop. This is also the case if I try performing the check inside OnDestroy.
I can't get (3) to work - I can't get my views to respond to WM_CLOSE.
Currently, my best solution is to do both (1) and (2), but this requires some smelly logic to prevent the app from prompting the user to save view changes twice on app shutdown.
Anyone know of a better way of doing this? Where is the correct place to hook in?
I'm not sure if it is your solution, but I have several views that can not close on condition and I handle them in DestroyWindow( ). And a message box there does come up over the app before it closes down. So try using DestroyWindow( ) rather than the destructor.
Concur.
ON_WM_DESTROY()
afx_msg void OnDestroy();
does the trick. It will not prevent the window from closing, but the question didn't request it.

Cant focus Firemonkey application when modal dialog open, unless modal dialog itself is clicked

I have an application in which users, upon logging in, are prompted with a modal dialog where they must choose the facility they wish to work out of. At this stage, the application looks like this:
The modal dialog is shown by calling this method:
bool __fastcall ShowFacChoiceForm()
{
TFacChoiceForm *Form = new TFacChoiceForm( Application );
bool Result = ( Form->ShowModal() == mrOk );
delete Form;
return Result;
}
In this case, TFacChoiceForm inherits from TForm so the ShowFacChoiceForm() function is calling the standard TForm.ShowModal method documented here.
The issue I am running into is that if my application loses focus, it cannot become the active window again unless the modal dialog itself is clicked. To better illustrate this, I will present the following scenario:
Lets say its Friday afternoon and I decide to goof off a bit and read some web comics. With my application open, I open up another window on top of it, like so:
Then, out of nowhere my boss comes in for a performance review, and I attempt to refocus my application by clicking somewhere on the main form. For example, at the position of this red X in the next image.
In the above image, I have clicked at the location of the red X. Now, both the form containing the web comic, and my application are inactive. Thus, my application does not come to the front of the screen.
However, if I am able to click somewhere on the modal dialog, like the red X in the following image...
...then my application comes to the front like one would expect.
To solve this, I have looked at using something like SetForegroundWindow from the Windows API, but I have not been able to find a way to trigger the event, since my main form does not fire events while I have a modal dialog open.
My question is, how can I make sure that if the user clicks anywhere on my application that it is brought to the front? Is there a property I can edit in my form to do this?
If you set modalresult to mrcancel in the ondeactivate of the modal dialog then the main form will get focus when its clicked. You can then check if the user is logged in the mousedown event of the main form and if not, show the modal dialog again.

C++ Modal dialog box continuing adding texts

I have dialog box and in it, it has OK and Cancel buttons then it also has a ListBox to display text in two columns. I would like to continue adding text into the ListBox after the dialog box is shown. How can I do that? Because after I call DoModal() to show the dialog box, the code does not continue to execute. Or should I create two threads (one is display dialog box while another thread continues adding text to dialog box)?
Make your dialog 'pull' the data it needs, maybe polling the data source with window messages every second, or every 100ms or so. Or, if you go the 'two threads' route (the better but more complicated option), have your data source post a window message to your dialog when there is new data, and then have the dialog fetch the data it needs. The reason for this is that it's much easier to use the existing CDialog infrastructure to get a window that behaves like an actual dialog, compared to building a modal window that acts like a dialog but isn't really.
If you do go the two threads route, your division of labor should be: one thread that does all the UI work (including showing the dialog), and one that 'generates' data and lets the UI know when there is new data. So the worker thread should not do anything related to the UI, nor call any methods on the dialog directly - you can't access windows from several threads. The only cross-thread window communication should happen through window message (i.e., use ::SendMessage()). So certainly don't do something like myDialog->m_theList.AddString("blah") from another thread, or something like it.
Showing a dialog box modally halts further execution until you close the box. Instead of showing it modal, show it normal but make it always on top so you can continue executing the code after the call to DoModal(). Alternatively, populate the box with all the info it will need before you call DoModal().
If you decide to take the "two threads" approach you will discover that the controls on MFC dialogs should not be updated or accessed from a thread other than the one that created the dialog. Even if you have pointers to these controls available in another thread it is not thread-safe to access them. This rule applies whether or not the dialog is modal.
Instead, your second thread would need to PostMessage or SendMessage to the dialog window, so the updates occur on the thread that created the dialog (most likely the main UI thread of the application).

Getting results from a non thread blocking message box?

Generally, message boxes work like this:
if(ShowMessageBox("Title","Text",MB_YES_NO) == MB_YES)
{
//the user responded yes
}
However, I'm working on a game where I have made the gui system, and when a messagebox is shown, there is still animation happening in the background so I cannot simply block the thread, the animation would stop.
Right now, the way it works is to show the message box, an IMessageHandler* must be provided and it is called with the dialog result.
I'm wondering if I'm overlooking something. Is there a better way to do this that might resemble more how it is usually done. How might other games approach it?
Thanks
There are multiple options, e.g...
Create a View-Model class that the message box reads from (title, message, button text) and writes to (result prior to closing), pass the VM to your message box before displaying it, then read result from VM after close.
(A better technique would to use a command pattern or place an event on the message box instead of passing VM to message box, then within command/event handler update VM).
Use a command pattern or an event to pass result from message box (prior to close) directly to caller (or to view model).
Use a show dialog style call to message box (blocking), however, do that on a separate thread, then write results to a place where main thread can read from.