Depending on a command line argument or virtual machine argument I'd like my application to start in an invisible mode. It does the same things in both cases, except that in invisible mode it simply doesn't display anything.
I can make the main program window invisible using JFrame.setVisible(false). However, then I have to find every place in the code, where for example a warning message pop-up is opened etc. (there are a lot of those!).
Is there a more general way to do that? May-be something like the headless mode (which of course throws HeadlessExceptions which is not what I want).
Thanks!
What does your applications architecture look like? If it is cleanly separated then create a new View layer that does nothing.
If it is tangled up together, the best option would be to un-tangle it and then create a new view layer that does nothing.
Do like this.
public static void main(String[] args){
boolean gui = true;
for (String s : args){
if (s.equals("--nogui")){
// Do not create GUI
gui = false;
break;
}
}
if (gui){
// Create the gui
}
}
If your presentation layer is tightly coupled with business logic you will have to do check in all your forms, and other visible classes. You should decouple your application, and than it would be as easy as calling one method.
In other case... well you will have a bunch of if else if.
Related
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.
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'm trying to close my main application user interface, but leave code running in my main() function that launched the application. Right now the problem I have is on a Mac the program name remains in Mac's menu bar even though there are no windows shown.
So basically in the code that would exit the application I have:
private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
//System.exit(0);
this.setVisible( false );
// Do something here to finish closing application.
}
The main function that starts the application looks like:
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
// NewApplication is a javax.swing.JFrame
new NewApplication().setVisible(true);
}
});
while (true) {
// Watch for user to relaunch UI and do lots of other tasks.
}
}
If I used System.exit(0) it would stop the entire JVM completely and stop running the stuff in the while loop. I cannot figure out how to exit the main application UI, stop from showing in the menu bar, but still run the while loop stuff.
The reason I'm trying to do this is I need something that will run continuously and sometimes the user will need to run a user interface that interacts with the stuff that is running. The stuff inside the while loop checks to see if they are trying to launch the user interface again (among other functions) and would reload it. One option is to make one program that runs continuously and use inter-process communication to talk between the user interface and a non-UI program, but I would need to pass lots of data back and forth so I don't like that option.
It appears there is not an easy way of doing this. For those that have the same problem here are a few options:
1) It looks like other programs I have do this by using Mac’s task bar (in the upper right corner of the screen). The only way you access the program is through a menu on the task bar. Even when you have UI’s shown you get to the UI through the task bar. The downside of doing this is that when the UI is shown you can’t use Cmd+Tab to get over to the window. This is non-intuitive for Mac users. If you want to use this option you can start the java jar file with the command line option “-Dapple.awt.UIElement="true”” and that will prevent the program from showing a menu ALWAYS, and then you'll want to create a task bar icon so the user can get to your program.
See How to hide the Java SWT program icon in the Dock when the application is in the tray
2) Have 2 programs that run, one with a UI and another without. They can communicate using interprocess communication (IPC) using files, sockets, etc. If you don’t have much data to pass between the processes, this is a good solution.
3) You could probably use JNI to remove the menu on the application after all the UI’s close. But you’ll need to dig into Mac’s Objective C language. I can't confirm you can actually do this though.
I've set up a Server which runs and accepts connections from my Remote Client, and now I'm working on my GUI.
Before anything else, my goal here is to create a nice looking client that will have a login screen (login/pw), and then a nice layout with my options/perhaps a chat box after the user has logged in.
I've searched a lot online and used this site to set up my server and get things working, but I've got a bit of a problem with the GUI/theory and hope someone here can guide me a bit.
At the moment, I've set up a class called ClientGUI which is called from my main class, and this produces a 420x240 size screen. After placing my login/password JTextField boxes here, is it "proper" to set up the other GUI's the way I've outlined below? I'm not sure if I should be putting them under one class or how I would advance from one GUI to the next. I'm thinking I should repaint and resize the screen as necessary, but I am not sure how to set it all up. A brief outline would be helpful (you don't need to give me exact code).
public class ClientGUI extends JFrame {
public ClientGUI() {
setSize(420,240);
setVisible(true);
setTitle("Title");
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
}
public loginGUI() {
//code for my login/pw boxes, images, listener for entering information
}
public afterlogginginGUI() {
}
paint() {
//not too sure about how this should be setup either. Should I do all my textfield
//and image work in paint()?
}
}
I have never made anything like this, so I have the feeling I'm not setting this up in an ideal way.
An alternative is to have a different java class extending JFrame for each 'screen' I want, but if I do it this way, would I do it like this?
In my main RemoteClient class:
main {
ClientGUI();
//display whatever
LoginGUI();
//listen for login info
if (loginIsValid) {
afterlogginginGUI();
}
}
I think you're thinking in to much of a linear fashion, where the code flows from A then to B then to C ... where in fact, Swing (and GUI's in general) are event driven...
C happens, so you do B, which triggers F so you do E ...
Start by creating a JPanel, onto this add your JTextField and JPasswordField, this will act as you basic login view. You could then add this to a JFrame or JDialog depending on your needs. You will need some way for the user to either "cancel" or "validate" their credentials.
Typically, I do this a separate view, as I never know where my poor "user details" pane might end up, but you could do this a single view (including the buttons within the "user details" pane), that will come down to your requirements.
You can use a CardLayout to switch from the "login" view to the "application" view. This has the benefit of maintaining only a single frame and prevents windows from been splashed all about the place...
I would, personally, separate the core functionality of the views to separate classes, this means you can simply create an instance when you need it and add it to whatever container you want.
I would recommend against extending from JFrame directly. This locks you into a single container (making it hard to re-use components or extend the program later) and you're not adding any new functionality to the class anyway...
Start by having a look at Creating a GUI With JFC/Swing.
You'll probably also be interested in How to Use CardLayout, How to Make Dialogs, How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners
You'll also need to have a look at Laying Out Components Within a Container
Because you're likely waiting for a response from the server at some point, you will need to have a look at Concurrency in Swing and Worker Threads and SwingWorker wouldn't hurt
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