I'm creating an application in which I test a certain number of interface features, and when an error occurs I would like an error message to show.
Then the application should take a screenshot of the entire screen, and finally the error message closes without any help from the user.
To this end, I tried to use JDialog as below:
JOptionPane pane = new JOptionPane("Error message", JOptionPane.INFORMATION_MESSAGE);
JDialog dialog = pane.createDialog("Error");
dialog.addWindowListener(null);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
Application.takeScreenshot();
dialog.setVisible(false);
I was wondering if there is a specific method to close it. I looked up the documentation and I can't seem to find it. I tried to find a relevant question on SO, but couldn't find one that addresses my problem.
I wonder if there is a way to get the window handle, and then close it using that, or simply send a "CLOSE" or "Press_ok" event to the window?
Edit: It seems to me as if the code entirely stops running when the messagebox shows, as if there was a Thread.sleep() until window is closed manually by the user.
If possible, a code sample would be helpful.
Thanks
Try to use ScheduledExecutorService. Something like:
JDialog dialog = pane.createDialog("Error");
dialog.addWindowListener(null);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
ScheduledExecutorService sch = Executors.newSingleThreadScheduledExecutor();
sch.schedule(new Runnable() {
public void run() {
dialog.setVisible(false);
dialog.dispose();
}
}, 10, TimeUnit.SECONDS);
dialog.setVisible(true);
[EDIT]
Regards to camickr comment, the documentation does not mention that a ScheduledExedcutorService executes on the Event Dispatch Thread. So better to use swing.Timer
JDialog dialog = pane.createDialog("Error");
dialog.addWindowListener(null);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
Timer timer = new Timer(10000, new ActionListener() { // 10 sec
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
dialog.dispose();
}
});
timer.start();
dialog.setVisible(true);
I've managed to fix it. It seems that by default, JDialog is Modal, meaning that it interrupts everything else until it's closed by the user. To fix this, I used the method:
dialog.setModalityType(Dialog.ModalityType.MODELESS);
When this is active, a simple .setVisible(false); is enough.
Anyways thanks for the help sorry for creating an unecessary question but I had been at it for hours until i found it. Hope it can help others.
Related
We have an javafx application developed mainly in java 1.7 and tested in 1.8. It was running fine until java 1.8u35. Now we discovered, JavaFx windows are not going to open in 1.8u40 after upgrade. Even worse, the modal windows are blocking the entire tab/ browser of being used. So the user is just able to close the browser using the task manager.
We use javafx.embed.swing.JFXPanel to embed jfx-code into swing legacy code.
I have completely no clue what might be the problem, as there are no errors displayed in client's java console.
UPDATE:
I reviewed the known issues list for java1.8 here. The only thing I would probably link to our issue is this bug:
BUG-RT-32597: The SwingNode class does not support High DPI displays.
So I tried lowering the screen resolution (1280x1024 to 800x600) but without success.
Does anyone faced a similar issue before and knows what might help?
UPDATE:
I tried to better track down the problem but with not much luck.
To make it more visible, this is basically whats going on on window loading:
public static void initWindow(JDialog dialog){
final JFXPanel jfx = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
System.out.println("JFXPanel");
}
});
Runnable r = new Runnable() {
public void run() {
AnchorPane root = new AnchorPane;
//... do some content loading
Scene scene = new Scene(root,width,height);
System.out.println("test");
}
};
dialog.add(jfx);
System.out.println("added jfx panel.");
dialog.pack();
System.out.println("packed jfx panel.");
dialog.setLocationRelativeTo(null);
System.out.println("loaded.");
}
I thought execution is going to stop somewhere, but its running through the entire function as usual. Nevertheless the window is not showing up.
UPDATE:
Not completely correct, my last comment, as I found out:
Around the above function, the following happens:
initWindow(this); //this is extending java.swing.JDialog
System.out.println("this comment is printed to console");
super.setVisible(true); //this is not executed properly. if removed, browser will not be blocked, but window doesnt show up either
System.out.println("this comment is not printed to console";
So, in general, there is the JDialog which gets packed with a JfxPanel. When calling setVisible() method from the JDialog class, the Application gets blocked but the window doesnt show up. Actually, in the thumbnail screen (alt+tab) it is shown as a container inside the application.
When removing the setVisible call, the browser does not get blocked, but also the window does not show up. Unfortunately, I did not find the JDialog class code to look up, what's going on inside setVisible().
Any ideas, what might be wrong with our setup or the setVisible method?
We had a similar problem. While comparing the Java sources of 1.8.0_31 and 1.8.0_45 we found out that there were some changes in the JFXPanel source code introduced with 1.8.0_45 that may cause problems in the following situation:
initialize modal JDialog with JFXPanel (executed on Swing's EDT)
initialize and set FX scene on JFXPanel in FX task (executed on FX Thread)
wait for FX task to be finished (wait on EDT)
pack() and show() JDialog (continued on EDT, blocks program execution)
continue with program execution after user closed JDialog (on EDT)
We use this workflow in order to wait for some user input being shown in a new modal JDialog and continue normal programm execution on EDT afterwards.
In 1.8.0_31, the preferred size of JFXPanel seems to be set in FX thread which allows JDialog.pack() to determine the correct bounds.
In 1.8.0_45, the preferred size of JFXPanel seems to be set not in FX thread anymore but in EDT after all pending AWT events are executed. So, when (4) is executed, JDialog.pack() does not know about the preferred size of the scene. As a consequence, the dialog has no content, or does not show up if undecorated as described in the original question above.
Here is a complete example to reproduce the different behaviour:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// create JDialog on EDT
final JDialog dialog = new JDialog((JDialog)null, "JDialog");
// initialize FX platform and create JFXPanel
final JFXPanel jfxPanel = new JFXPanel();
// add resize listener for JFXPanel
jfxPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// not called in 1.8.0_45
System.out.println("JFXPanel.getSize(): "+jfxPanel.getSize());
}
});
// set FX Scene on JFXPanel and wait until finished
runAndWait(new Runnable() {
public void run() {
Text text = TextBuilder.create().text("JavaFx content").y(20).build();
Group root = new Group(text);
Scene scene = new Scene(root);
jfxPanel.setScene(scene);
}
});
// show undecorated modal JDialog with FX content
System.out.println("JFXPanel.getPreferredSize(): "+jfxPanel.getPreferredSize());
dialog.setUndecorated(true);
dialog.add(jfxPanel);
dialog.pack();
dialog.setModal(true);
System.out.println("JDialog.setVisible()");
dialog.setVisible(true);
}
});
}
private static void runAndWait(Runnable r) {
try {
FutureTask<Object> task = new FutureTask<Object>(r, null);
Platform.runLater(task);
task.get();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
When running this program, componentResized() is called only in 1.8.0_31 but not in 1.8.0_45.
A possible fix while keeping the synchronous program workflow on EDT is to replace JDialog.pack() with JDialog.setSize(...), e. g. by setting a constant size or by using the size of the FX scene that could be determined using root.getBoundsInLocal().
I encountered the same behaviour described by #Peter using 1.8.0_121.
I was able to get dialog.pack() to work using a window listener.
dialog.addWindowListener( new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
((JDialog)e.getSource()).pack();
}
});
I've been validating a swing application that runs on an applet for mac osx.
During this validation I found the following issues with the modal dialogs:
When a dialog is open and is setModal(true) it blocks the content of the root window, but if you click somewhere on the root window, the dialog goes under it, but it should remain on the top of the root window.
If the dialog has a JTextInputField it does not receive focus even when you click on it.
So I created a small program to show the problem. Can you please help me to understand what is wrong here?
package com.macosx.tests;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class DialogExample extends JApplet{
private static final long serialVersionUID = 1L;
private JPanel panel;
private JButton openDialogBtn;
private void doStart() {
panel = new JPanel();
panel.setPreferredSize(new Dimension(500,500));
openDialogBtn = new JButton("open dialog");
openDialogBtn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
ModalDialog dialog = new ModalDialog(panel, true);
dialog.setVisible(true);
}
});
panel.add(openDialogBtn);
setContentPane(panel);
}
class ModalDialog extends JDialog {
private static final long serialVersionUID = 1L;
public ModalDialog(Component parent, boolean modal) {
Dimension dimensionParentFrame = parent.getSize();
setSize(new Dimension((parent == null) ? 300 : dimensionParentFrame.width / 2, 75));
setModal(modal);
setModalityType(ModalityType.APPLICATION_MODAL);
JTextField txtField = new JTextField();
add(txtField, BorderLayout.CENTER);
}
}
#Override
public void start() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
doStart();
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Use the above to create a .jar file (test.jar). Once that is done, create a html file with the following content:
<html>
<head>
<title>Dialog test Applet</title>
</head>
<body>
<applet id="DialogTestApplet" height="800" width="600"
code="com.macosx.tests.DialogExample"
archive="test.jar">
</applet>
</div>
</body>
</html>
When this is done, run the html file. You'll see an applet with a gray background and with a button. Then try to:
click on the button to open the dialog. After that, click somewhere on the gray area: the dialog goes under the browser window but it should remain on the top, right?
click on the button to open the dialog. After that click on the textfield of the dialog and try to write something: the textdialog does not receive focus.
So, what am I doing wrong here? Can someone with a mac computer test this please?
Thanks
Specs:
java.vendor Oracle Corporation
java.version 1.7.0_07
os.name Mac OS X
os.version 10.7.4
browser firefox 15
NOTE: please note that this is only happening when the applet runs on the browser and only on mac osx.
I found another workaround. When the window is opened, show an optionpane for a few milliseconds and close it. It give the focus to the optionpane and then back to the dialog, allowing to ignore the bug.
Add this snipet of code to your dialog constructor and it should work:
addWindowListener(new WindowAdapter(){
public void windowOpened(WindowEvent e){
JOptionPane pane = new JOptionPane();
final JDialog dialog = pane.createDialog("Please Wait");
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
timer.setRepeats(false);
timer.start();
dialog.setVisible(true);
}
You should put an "owner" window on your ModalDialog. To do that, you must call super(owner) in your ModalDialog constructor and you can retrieve the parent window of your component parent with SwingUtilities.getWindowAncestor(parent).
not Mac/OSX user but this is common issue about Focus and JDialog,
there are another issues in the case that JDialog is created on Runtime,
Focus is asynchronous based on properties came from Native OS
create this JDialog only once time and re_use this container for another action
JDialog#setVisible should be wrapped into invokeLater() too
is possible to force the Focus by JTextField#setText(JTextField#getText()) wrapped into invokeLater()
there is Dialog Focus, one of great workaround by #camickr
I confirm, I have the same bug with an old applet running in JDK7 on OS X. As the poster mentioned, the bug is seen only with the applet running in the browser (ff) and not with the appletviewer.
I can verify that this is a problem for Java 1.7 Update 7+ on the Safari 6 and Firefox running on Mountain Lion. Curiously it is not a problem on earlier versions of Safari that run on Lion but it is a problem in Firefox on the older OS. I am pretty desperate to find a fix for this as a number of my applet users are on Macs. One workaround that I have found (that is not sufficient by any means) is to minify the window and then reopen it. The textfields/textareas then become editable. Hopefully, we can find a better solution that gets around this annoying requirement.
I experienced the same problem on Mac with Java 7 update 9 with Safari and Firefox. When I opened a JDialog which contained a JTextField the JTextField was inaccessible.
I did find a solution. I inserted a delay from when the user pressed the “show dialog button” to executing the code that shows the button.
For example:
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae){
TitleDialog dialog = new TitleDialog(main.findParentFrame()); // My JDialog which contains a JTextField.
dialog.setVisible(true);
}
};
javax.swing.Timer timer = new javax.swing.Timer(1000, al);
timer.setRepeats(false);
timer.start();
I experienced that if the delay was to short the solution would not work.
If one uses SwingUtilities.invokeLater instead of javax.swing.Timer it will not work. Maybe the delay of SwingUtilities.invokeLater is too short.
I found one more workaround. When JDialog is invoked from JavaScript it has a focus.
Create an applet's method which will show a dialog
Call this method from JavaScript.
Hope, it helps. By the way, web start samples from Java tutorial have the same issue http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html
I want to use the workaround above (to open dialog from the dialog), but without showing any dialog.
Here is a code for not visible dialog.
final JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.setSize(0, 0);
dialog.setModal(true);
dialog.pack();
I have found a solution.
GetDirectory varGetDirectory = new GetDirectory(new JFrame(),true);
varGetDirectory.setVisible(true);
GetDirectory is JDialog containing a JFileChooser.
The weird thing is that all JDialog object should be called using new JFrame() as parent, otherwise clicking from one parent window, will bring the top modal JDialog backwards in the zOrder and somehow it cannot be set on top anymore.
My problem was the same as above. When I have created the JDialog from another JDialog, the new dialog appeared behind the other.
To bring it to top I have set the parent of all JDialogs as described above and it worked according to what expected.
How do you close a java application from the code?
You call System.exit:
System.exit(0);
I believe that by most standards, System.exit() is a not very OOP way of closing applications, I've always been told that the proper way is to return from main. This is somewhat a bit of a pain and requires a good design but I do believe its the "proper" way to exit
If you're terminating a Swing app, I would do an EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
before System.exit(0). This is better since you can write a Window Listener to make some cleaning operations before actually leaving the app.
That window listener allows you to exit the app from the code:
public void windowClosing(WindowEvent e) {
displayMessage("WindowListener method called: windowClosing.");
//A pause so user can see the message before
//the window actually closes.
ActionListener task = new ActionListener() {
boolean alreadyDisposed = false;
public void actionPerformed(ActionEvent e) {
if (frame.isDisplayable()) {
alreadyDisposed = true;
frame.dispose();
}
}
};
Timer timer = new Timer(500, task); //fire every half second
timer.setInitialDelay(2000); //first delay 2 seconds
timer.setRepeats(false);
timer.start();
}
public void windowClosed(WindowEvent e) {
//This will only be seen on standard output.
displayMessage("WindowListener method called: windowClosed.");
}
If you're running an application, System.exit will work.
System.exit(int);
In an applet, however, you'll have to do something along the lines of applet.getAppletContext().showDocument("landingpage.html"); because of browser permissions. It won't just let you close the browser window.
You use System.exit(int), where a value of 0 means the application closed successfully and any other value typically means something was wrong. Usually you just see a return value of 1 along with a message printed to sysout or syserr if the application did not close successfully.
Everything is fine, application shut down correctly:
System.exit(0)
Something went wrong, application did not shut down correctly:
System.err.println("some meaningful message"); System.exit(1)
I wrote a simple application and I want show delay of it with JProgressBar Plese help me ;
I want show JProgressBar with Joptionpane , with a cancel button and it should be modal
this is my source code :
class CustomFrame extends JFrame {
private JProgressBar progressBar;
public CustomFrame() {
long start = System.currentTimeMillis();
myMethod();
this.getContentPane().setLayout(null);
this.setSize(200, 200);
//JOptionPane. ?????
this.setTitle("JFrame");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
long end = System.currentTimeMillis();
System.out.print("\nTime: " + (end - start));
}
public void myMethod(){
try {
java.io.File file = new java.io.File("i://m.txt");
BufferedReader input =
new BufferedReader(new FileReader(file));
String line;
while ((line = input.readLine()) != null) {
if (line.indexOf("CREATE KGCGI=") != -1 ){
System.out.println(line);
}
}
input.close();
}
catch(Exception e){
e.printStackTrace();
}
}
Thanks ...
There are a couple things that you will need to do to get this to work:
You should be aware of threading issues in Swing. Your GUI painting should be done on the EventDispatchThread and disk I/O should be done in a worker thread. See this tutorial, the SwingWorker JavaDoc, and SwingUtilities.invokeLater for more detail
You will then want to get the size of your file (file.length())to determine how to scope your progress bar (myProgressBar.setMaximum(length))
When you iterate over the lines in your file, you will want to trigger an update to your progress bar (myProgressBar.setValue(myProgressBar.getValue()+lineLength)).
A couple points by way of critique:
your constructor shouldn't go off and do all of your work (ie load your file and pop up an option pane with the ability to cancel. the constructor should just do the work needed to create the object. you might want to consider having your constructor create your class, and then have the work that needs to be done to be called separately, or within something like an init() method.
It isn't clear what you are doing with the JFrame as superclass. JOptionPane is a class that will pop up a very basic modal dialog with some text, maybe an icon or input field. It isnt a panel that is embedded in a dialog.
As JOptionPane is a very basic construct for creating a basic message dialog, it might be easier to use a JDialog, which can also be made modal. JDialog will allow you to add buttons as you please, where as a standalone JOptionPane will require you to use Yes/No, or Yes/No/Cancel or OK/Cancel etc.
If you still want to use JOptionPane, and only show a cancel button, you can instantiate a JOptionPane (as opposed to using the utility show* methods), with the progressbar as the message, and the JOptionPane.CANCEL_OPTION as the optionType param. You will still need to put this into a JDialog to make it visible. See this tutorial for more details:
JOptionPane (constructor)
Creates a JOptionPane with the specified buttons, icons, message, title, and so on. You must then add the option pane to a JDialog, register a property-change listener on the option pane, and show the dialog. See Stopping Automatic Dialog Closing for details.
I have problem currently for my swing reminder application, which able to minimize to tray on close. My problem here is, I need JOptionPane dialog to pop up on time according to what I set, but problem here is, when I minimize it, the dialog will pop up, but not in the top of windows when other application like explorer, firefox is running, anyone know how to pop up the dialog box on top of windows no matter what application is running?
Create an empty respectively dummy JFrame, set it always on top and use it as the component for the JOptionPane instead of null. So the JOptionPane remains always on top over all other windows of an application. You can also determine where the JOptionPane appears on screen with the location of the dummy JFrame.
JFrame frmOpt; //dummy JFrame
private void question() {
if (frmOpt == null) {
frmOpt = new JFrame();
}
frmOpt.setVisible(true);
frmOpt.setLocation(100, 100);
frmOpt.setAlwaysOnTop(true);
String[] options = {"delete", "hide", "break"};
int response = JOptionPane.showOptionDialog(frmOpt, msg, title, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, "delete");
if (response == JOptionPane.YES_OPTION) {
removeRow();
}
frmOpt.dispose();
}
Old post, but I was struggling with this.
My problem was more with Javafx allowing the JOptionPane to go behind the current Java window.
Therefore I used the following which does what the original poster asked by putting the JOptionPane in front of all windows; even JAVAFX.
Firstly the old JOptionPane:
JOptionPane.showMessageDialog(null, "Here I am");
Now an JOptionPane that stays in front:
final JDialog dialog = new JDialog();
dialog.setAlwaysOnTop(true);
JOptionPane.showMessageDialog(dialog, "Here I am");
And for fun here is everything in one long line:
JOptionPane.showMessageDialog(
((Supplier<JDialog>) () -> {final JDialog dialog = new JDialog(); dialog.setAlwaysOnTop(true); return dialog;}).get()
, "Here I am");
You can make a static method some where that will return the JDialog for you and then just call it in the JOptionPane to clean up your code a bit.
Are you using one of the canned JOptionPanes? (Like JOptionPane.showCOnfirmDialog(...))
You may want to look at extending JDialog and making your own dialog panel, and then calling myDialog.setAlwaysOnTop(true);
Windows is blocking this operation since XP.
The scenario before was like:
Your a tiping in some text in an editor and not recognize that another dialog is coming to front when you are tipping the text. The coming dialog gets the focus and you are tiping in the new dialog. Maybe you click enter after you are ready and do this in the wrong dialog, which is asking whether you realy want to delet your hard disk ;)
The come to front call in java is only working for java windows.
The possibibilty to notify the user of a new window is to implement a Frame, which will highlighted/flashing in the windows task bar.
Correction the post above..
I have resolve my problem as below:
this.setVisible(true); // show main frame
MyDialog dialog = New MyDialog(this, true); // show my custom dialog
dialog.setVisible(true);
this.setVisible(false);
it works fine for me :)
You might think about using a JFrame instead. It may give you a little more flexibility.
If you are using a JFrame and you want it to popup on top of the other windows use:
myFrame.setVisible(true);
myFrame.setState(Frame.NORMAL);
The setState will show the window to the user if it was in minimized state previously.