I was recommended to use InteractionDialog rather than Dialog, but I'm failing to see the advantages. What I can see is a problem. What I need is letting the user enter a PIN or whatever and wait for their answer. This is needed both on the EDT thread (the user choose to save the PIN) and on other threads (a web page requires the PIN for login).
With Dialog,
I can call it from the EDT thread and it works nice.
When on a different thread, I can be trivially adapted by a one-liner in the callee (see getFromGui in my linked question).
With InteractionDialog,
I can use it easily from other threads via some simple wait/notifyAll magic.
I can't use it from the EDT thread, except via callbacks like okBtn.addActionListener(...), which is verbose and ugly.
So I am confused and asking:
What do I gain from the InteractionDialog?
Is there a simple way how to use it uniformly no matter what thread I am on?
There are two separate things here:
Modality
How it works
A dialog can be modal or non-modal but it isn't interactive like an InteractionDialog. The modal dialog blocks the EDT internally using InvokeAndBlock so the current thread stops until there's a response from the dialog. This is convenient but has some edge case issues. E.g. the event that launched the dialog might trigger other events that would happen after the dialog was dismissed and cause odd behavior.
But that's not the big thing in modality. Modality effectively means the form behind you "doesn't exist". Everything that matters is the content of the dialog and until that is finished we don't care about the form behind. This core idea meant that a dialog effectively derives form and as such it behaves exactly like showing another form effectively disabling the current form. What you see behind the dialog is a drawing of the previous form, not the actual form.
Text fields can pose a problem. Because the way the dialog is positioned (effectively padded into place within its form using margin) the UI can't be scrolled as text field requires when the virtual keyboard rises. Since people use dialogs in such scenarios we try to workaround most of these problems but sometimes it's very hard e.g. if the dialog has a lot of top margin, the virtual keyboard is open and covering it. Or if the user rotates the screen at which point the margin positioning the dialog becomes invalid.
Note that in InteractionDialog Some of these issues such as the margin to position also apply.
Now InteractionDialog is a completely different beast that sprung out of a completely different use case. What if we want a dialog such as a "color palette that floats on top of the ui?
We can move it from one place to another but still interact with the underlying form. That's the core use case for InteractionDialog. As such modality is no longer something we need so it was never baked into InteractionDialog although it technically could have been (but it doesn't make sense to the core use case).
It's implemented as a Container placed into the layered pane of the current form so the form around it is real. Because the form is "live" layout works better and the removal of modality makes some edge cases related to editing slightly better. There are still some inherent problems with dialog positioning and rotation though. It also allows you to click outside of the dialog while input is ongoing which might be a desirable/undesirable effect for your use case.
Overall I try to use dialogs only for very simple cases and avoid input when possible. If I use input I never use more than one field (e.g. no-username and password fields) so I won't need to scroll. These things work badly for native UIs as well e.g. with the virtual keyboard obscuring the submit button etc. Since those behaviors are very hard to get right for all resolution/virtual keyboard scenarios.
Based on the answer from Shai, I wrote a form working as the base class for most of my dialogs. Basically, it shows the content from the subclass and adds the "OK" and "Cancel" buttons.
There's a method for use from the EDT thread like
public void showAndThen(BooleanConsumer consumer) {
assert CN.isEdt();
...
okBtn.addActionListener(a -> {
lastForm.show();
consumer.accept(true);
});
cancelBtn.addActionListener(a -> {
lastForm.showBack();
consumer.accept(false);
});
}
where BooleanConsumer is a trivial void accept(boolean b) interface.
There's another method for use from other threads
#Override public final boolean ask() {
assert !CN.isEdt();
final BooleanTransfer transfer = new BooleanTransfer();
CN.callSerially(() -> showAndThen(result -> transfer.set(result)));
return transfer.await();
}
where BooleanTransfer is a two-method class where the thread calling set passes a boolean to the thread calling await.
Related
My JavaFX 8 application has to doStuff() when it gets focused. That's pretty simple:
primaryStage.focusedProperty().addListener((observable, wasFocused, nowFocused) -> {
doStuff();
});
However, when I display a dialog and user closes it, doStuff() fires. I want it to fire only when user switches from another app to mine, for example Alt+Tab from a browser.
In other words, I want to doStuff() iff other app's window loses focus and my app's window gets focus.
Is it possible?
Edit: Answers posted by FibreFoX and Appelemac require explicitly performing additional step before showing a dialog. This solution is far from perfect, because I (or any developer, in general) have to remember about this step before showing a dialog. Forgetting about it will introduce hard to find bugs.
Extending Dialog to do it automatically isn't an option, because I want to use built-in dialogs that already extend original Dialog.
That's pretty basic feature, I'd be surprised if there's no easy way to achieve this in JavaFX.
You could use a global boolean when opening such dialogs, and only when that global switch is true/false/whatever-you-choose then you could react on that state-switch.
public class GlobalDialogMemory{
public static boolean dialogShown = false;
}
When using CDI you could inject the application-scoped current instance (but you should use getter/setter and non-static booleans instead ;)
I'd suggest adding a listener to your Dialog, which then allows you to not doStuff() if the Dialog was just closed/lost focus.
Easiest way I can think of is setting an Instant (with Instant.now) when the dialog is closed, and if the application regains focus, create another Instant, and check whether the Duration.between(instantLostFocusDialog, instantGainedFocusApp).getSeconds() exceeds 1 (or add getNano() to that to be more specific). Only then would you doStuff()
I am working on an application that will have the following feature:
The application will have a "Load Image" button to open an image and settings modal dialog. It will need to block until that dialog returns, either with the results of the processing or null if the user changed his mind.
The image and settings dialog will allow the user to select an image using a JFileChooser dialog and to specify to what level of detail to process the image. Clicking a "Load" button will open a load dialog.
The load dialog needs to be a custom-designed dialog that reports in detail about the time-consuming processing of the image. If the user allows the processing to finish, it needs to close and return the object back to the original dialog, which needs to close and return that object back to the application. If the user decides it is taking too long to perform the processing, he can cancel the load, closing the loading dialog and returning to the image and settings dialog.
Conceptually, this does not seem so difficult to me. However, when I try to determine how to get this to work within Swing, somehow I cannot put it together. From what I've read, GUI components need to be instantiated in Swing's event thread since many of them are not thread-safe. These same components need to block on calls similar to (but not the same as, since I need to write custom components) the JOptionPane.showInputDialog() methods. But these calls need to instantiate new components in the event thread and wait for events to occur in the event thread before returning a value to the application. Compounding this with the fact that I need a dialog to pop up from a dialog, I feel quite lost.
I have read the Java Tutorial on dialogs and several posts on StackOverflow and other sites trying to determine how I can design classes that work correctly. Somehow, I just don't understand how this can work at all (isn't the event thread going to sleep after the first blocking call?), and how I can write the custom classes I need to make this work. Frankly, I am not certain I understand my confusion enough that I was able to explain it.
Could someone please explain what goes on under the hood when modal dialogs have been instantiated? How I can write dialog classes that behave the way I need as described above?
The application will have a "Load Image" button to open an image and settings modal dialog. It will need to block until that dialog returns, either with the results of the processing or null if the user changed his mind.
OK, so this dialog will need to be modal. That much we know.
The image and settings dialog will allow the user to select an image using a JFileChooser dialog and to specify to what level of detail to process the image. Clicking a "Load" button will open a load dialog.
OK, so the load dialog will need to be modal off of the image and settings dialog. No biggie there either.
The load dialog needs to be a custom-designed dialog that reports in detail about the time-consuming processing of the image. If the user allows the processing to finish, it needs to close and return the object back to the original dialog, which needs to close and return that object back to the application. If the user decides it is taking too long to perform the processing, he can cancel the load, closing the loading dialog and returning to the image and settings dialog.
OK, so the load dialog code will need to instantiate and execute a SwingWorker to do the time-consuming image processing in a background thread, and then have the SwingWorker use its publish/process method pair to push information about the processing details back to the load dialog.
...From what I've read, GUI components need to be instantiated in Swing's event thread since many of them are not thread-safe.
Correct.
These same components need to block on calls similar to (but not the same as, since I need to write custom components) the JOptionPane.showInputDialog() methods.
And this is what a modal JDialog allows you to do. Another option to keep in mind is to use a JOptionPane and pass in a JPanel with whatever GUI you want the JOptionPane to display. JOptionPanes are surprisingly flexible and useful.
But these calls need to instantiate new components in the event thread and wait for events to occur in the event thread before returning a value to the application. Compounding this with the fact that I need a dialog to pop up from a dialog, I feel quite lost.
Again it's simple. The load dialog will call a SwingWorker which will communicate back to the load dialog.
Could someone please explain what goes on under the hood when modal dialogs have been instantiated?
Now you may be asking a bit too much for the volunteers on this site to do, since this question would probably require someone to write a complete tutorial to answer, and it has been asked and answered before, so the information should be discoverable by you. If you really want to see what is going on under the hood, you should first do the preliminary research on the subject yourself, look at the source code, and if still stuck, ask a much more specific and answerable question after first doing your own due diligence work.
Modal dialogs started from the primary event loop spawn a secondary event loop that remains active while the primary loop is blocked. See java.awt.SecondaryLoop.
So my question, as stated (sort of) in the title, is about the behaviour in some respects of the Javafx (namely 2.2) Popup. Most of the time, you get a popup, and you give it a window to act as it's parent, you give it some scene, and it tends to act relatively independently.
This is all fine, however, in my case, I needed a popup that would anchor itself to a particular stage (window), at a particular location, when an event happened. That popup would then, in turn, disappear when the window disappeared (minimize, off screen, whatever), moved when it would, and in all essence and functionality, be a physical extension of the window, just with a custom shape.
Now of course, there are a lot of nuances with that, and everything for the most part, works great. The only thing I can't seem to figure out is that normally in a platform like Windows 7 64 bit, say. You open two programs, alright. Then if the programs are overlapping a little bit, whichever has focus gets to have the entire program displayed, whereas the other one gives the impression of being 'behind' the other window. (Whether or not windows actually renders application graphics 'behind' a window when another has focus on the same spot, I'm not sure.). Normally, javafx also supports this functionality just fine. But for some reason, The Popup class in javafx (see docs here) doesn't do that. It's always on top of whatever it's displayed with, without exception. For the point of completeness, here's my pretty straightforward popup code (at least the part pertaining to showing it and it's properties):
Popup myPop = new Popup();
//************************Popup Property Setter**************************
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
myPop.setWidth(width);
myPop.setHeight(initialHeight);
myPop.setAutoHide(false);
myPop.setAutoFix(false);
myPop.setHideOnEscape(false);
myPop.setX(xLocation);
myPop.setY(yLocation);
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//**********************end of Popup Properties**************************
myPop.getContent().add(main_anchor);
myPop.show(FileChooserWindow.get_stage());
main anchor has some various components i include inside of the 'myPop' popup, and FileChooserWindow is a non-null parent window that will be open at the time of this method calling without exception.
Here is a screenshot as well of the behaviour I'm referring to. Notice the highlighted text in the pdf, that is where my cursor currently has focus. Also, the window that the popup is anchored to can be seen in the back of the pdf poking out from the left.
Any help you guys can give would be much appreciated. I really hope I don't have to check for active processes and their location relative to the popup, that's getting dangerously close to my knowledge border, and sounds like a total PITA.
So, after toying with this for a few more days, I have a rough workaround, although it is a hack in the full meaning of the term.
Although the popup behaviour is still mystifying me, I can simulate a fix in this behaviour by adding a changeListener to the stage to which it is attached (since I didn't want the popup to close if it's parent window had focus, only if anything BUT the popup and it's parent got focus).
See code as follows:
FileChooserWindow.get_stage().focusedProperty().addListener(new ChangeListener<Boolean>(){
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
if (!newValue){
if(AutogenPopup.popupReturner().focusedProperty().get()){
AutogenPopup.popupReturner().hide();
}
}else{
if(FileChooserController.refreshAutoPopup && FileChooserController.autoGen_flag){
AutogenPopup.popupReturner().show(FileChooserWindow.get_stage());
}
}
}
});
never mind some of those flags that I'm checking against, they are simply some internal tools to make sure that the popup only appears when the program is in the proper state.
Now, one interesting thing to note. The AutogenPopup.popupReturner().focusedProperty().get()
Seemed to be returning true when the popup's parent window LOST focus. Which is quite counter-intuitive to me, and in my opinion, is even a touch buggy. Now, this does not simulate the behaviour of a modern operating system where a window can slide in and out of focus incrementally, since the popup will just completely disappear upon it's parent window losing focus. But seeing as how my popup just displays additional text entry on the side of the main window, this is an acceptable compromise until I think of a better solution. (Perhaps the better solution is not to use a popup at all, and instead skin a window to act in a popup-y fashion).
Anyway, I hope this helps someone, maybe eventually there will be a more fine-grained way to control this popup functionality.
How do buttons in software written in Java work?
For example the above screenshot: when the user clicks different buttons, different algorithms are run on user-inputted data (it's a data analysis application) and the output is displayed. Just getting started writing Java GUI's though, it all seems like magic to me -- is there one ActionListener for every pane? Does it listen for different ActionCommands of the different buttons and execute the algorithm right within the actionPerformed() method (it seems a little nonintuitive to me to execute an algorithm in a method independent of data...i.e. the button doesn't know what data it's dealing with?). So far, all the action listener tutorials I've read online have merely printed something when the button is pressed...
What's the general structure for connecting button, actionlisteners, and actual actions performed in the background?
Thanks in advance.
The usual way is to have one action listener per button. The Statistics panel has access (via one of its fields), to the data it needs to read and modify). So, the handling of the first button in this panel could look like:
private void initButtonListeners() {
this.averageDegreeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
computeAverageDegree();
}
}
// other buttons...
}
And the computeAverageDegree() method could look like
private void computeAverageDegree() {
double result = this.statistics.computeAverageDegree();
this.averageDegreeLabel.setText(formatDoubleToString(result));
}
My personal preference is to do almost nothing in the UI, but move it all to the model/controller side (not sure what the best name is as it is seldom pure MVC).
I think that everything you do in the UI should be doable through the API as well. Benefits are easier testing, redesign of the UI is possible without messing up your logic, easy to perform the heavy work on background threads, ... .
A good read describing this is the Humble Dialog article. Not really Swing specific, but applicable to all sort of UI's.
To answer your questions:
is there one ActionListener for every pane?
No, typically you have an Action (or ActionListener) for each button. I prefer to use Action instances as they are far more reusable then the typical anonymous ActionListener (and easier to test as well)
Does it listen for different ActionCommands of the different buttons and execute the algorithm right within the actionPerformed() method
Certainly not. Doing heavy calculations in that method will block the Swing UI thread (the Event Dispatch Thread), which results in a non-responsive UI while the calculations are ongoing. Showing progress becomes also impossible. Calculations are typically done on a worker thread, launched when your Action is triggered (for example using a SwingWorker). This is explained in the Concurrency in Swing tutorial.
it seems a little nonintuitive to me to execute an algorithm in a method independent of data...i.e. the button doesn't know what data it's dealing with?
The button should not know about the data. The data is typically stored in the model. The UI is only displaying it, but does not contain it (unless it is input just provided by the user). The button should just know what to call on the model. The model does whatever it has to do and fires an event. The UI picks up that event and updates itself.
At least, that is how Swing is designed (for example JTable and its TableModel). I so no good reason to not follow that model when making your own Swing UI's
I'm making custom dialogs that I want to pop up and disable the main shell behind it so that it cannot be clicked while the dialog is active.
My initial plan was something like as follows:
shell.setEnabled(false);
doDialogStuff();
shell.setEnabled(true);
this worked but as I close the dialog, it loses focus of the shell that was open before the dialog. I managed to sort of fix it by adding
shell.setFocus();
after the last line but this is messy and causes the screen to flicker as the window loses and then gains focus in a split second, also, it sometimes doesn't regain focus and I can't understand why :/
Is there a better way to disable the background window without it losing focus.
Thanks in advance SO peeps
You should create a custom dialog based on this tutorial.
This way you just have to set the modality of the dialog to whatever you need exactly and the dialog will take care of the rest for you.
This should be helpful as well (Javadoc of Shell):
The modality of an instance may be specified using style bits. The modality style bits are used to determine whether input is blocked for other shells on the display. The PRIMARY_MODAL style allows an instance to block input to its parent. The APPLICATION_MODAL style allows an instance to block input to every other shell in the display. The SYSTEM_MODAL style allows an instance to block input to all shells, including shells belonging to different applications.
The proper thing to do is create the dialog as a modal window. When you create the dialog's shell you should do something like
dialogShell = new Shell(mainShell, PRIMARY_MODAL | DIALOG_TRIM);