23

I'm running some code in Java on Ubuntu 12.04 LTS 64 Bit (with Gnome Shell), using Oracle JDK 1.8.0_05 via NetBeans8.0.

The following function works perfectly when called either in Main or in an otherwise empty Java Project, however when called from any JavaFX application, it causes the window to freeze and stop responding (although the project complies perfectly), requiring it to be Force Closed.

Can anyone suggest any issues with what I've written which might be causing an issue or loop?

Alas, due to the mode of failure, there is no error message that I can supply or analyse.

Any suggestions gratefully received, thanks in advance.

   public static void desktopTest(){

            Desktop de = Desktop.getDesktop();

            try {
                de.browse(new URI("http://stackoverflow.com"));
            }
            catch (IOException | URISyntaxException e) {
                System.out.println(e);
            }

            try {
                de.open(new File("/home/aaa/file.ext"));
            }
            catch (IOException e){
                System.out.println(e);
            }
            try {
                de.mail(new URI("mailto:email@example.com"));
            }
            catch (URISyntaxException | IOException e){
                System.out.println(e);
            }
}
Wren
  • 633
  • 5
  • 13

5 Answers5

40

I also had the same problem and this solution works for me:

if( Desktop.isDesktopSupported() )
{
    new Thread(() -> {
           try {
               Desktop.getDesktop().browse( new URI( "http://..." ) );
           } catch (IOException | URISyntaxException e1) {
               e1.printStackTrace();
           }
       }).start();
}
Alex K
  • 525
  • 5
  • 6
  • The important part here is `Desktop.isDesktopSupported()`. There seems to happen some kind of initialization. Without that it does not work. This answers should be marked as accepted answer. – ST-DDT Sep 06 '16 at 13:13
  • 7
    What made it work for me was creating a new thread - that appears to be necessary. – Josh Larson Feb 11 '17 at 18:24
  • 1
    It seems "Desktop.open()" has the same problem and solution. Thanks, Alex :). – jamie May 05 '17 at 21:22
3

I resolved problem with...

 public static void abrirArquivo(File arquivo) {
    if (arquivo != null) {
        if (arquivo.exists()) {
            OpenFile openFile = new OpenFile(arquivo);
            Thread threadOpenFile = new Thread(openFile);
            threadOpenFile.start();
        }
    }
}

private static class OpenFile implements Runnable {

    private File arquivo;

    public OpenFile(File arquivo) {
        this.arquivo = arquivo;
    }

    private void abrirArquivo(File arquivo) throws IOException {

        if (arquivo != null) {
            java.awt.Desktop.getDesktop().open(arquivo);
        }

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            abrirArquivo(arquivo);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
Douglas
  • 31
  • 2
2

I also have this same problem. I found out that if I call the Desktop.open() method from a new thread, the file will open after I close the JavaFX application window, but that doesn't help much.

If you put

SwingUtilities.invokeLater(() -> System.out.println("Hello world"));

in to your main method after your launch(args) call, it also won't get called until after you close the JavaFX application.

It seems like there's some kind of concurrency issue between the JavaFX application and Swing.

On Ubuntu you can try

xdg-open filename

from your JavaFX app.

As far as I can tell, your code should work.

  • Thanks for this, nice to know I'm not going mad -- I know about xdg-open and it works fine, but I'm only using Java to guarantee easy cross-platform operability... But it's falling pretty flat on its face at the moment - can I ask what environment you're running? Thanks! – Wren May 02 '14 at 10:04
1

There is a new way to handle this in JavaFX. The only downside I see is you need to instantiate a HostServicesDelegate using the Application singleton.

HostServicesDelegate hostServices = HostServicesFactory.getInstance(appInstance);
hostServices.showDocument("http://www.google.com");
Gabriel Féron
  • 108
  • 1
  • 8
  • 4
    Using `com.sun` APIs such as `com.sun.deploy.uitoolkit.impl.fx.HostServicesFactory` is inadvisable as they are not guaranteed to be available in future JavaFX versions. Instead use the public [`Application::getHostServices()`](https://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#getHostServices--) API. – jewelsea Jun 23 '15 at 07:52
1

Encapsulate it on a System thread:

    final String url = "www.google.com";
    final Hyperlink hyperlink = new Hyperlink("Click me");
        hyperlink.setOnAction(event -> new Thread(() -> {
            try {
                Desktop.getDesktop().browse(new URI(url));
            } catch (IOException | URISyntaxException e1) {
                e1.printStackTrace();
            }
        }).start());
  • Can you provide additional explanation? What causes the problem? Why does this solution work? – Jon Surrell Jun 23 '15 at 07:35
  • I'm sure that JavaFX thread gets blocked with `Destktop.getDesktop().browse()`, but I don't know the reason. JavaFX thread should only be used for short tasks related with the view (Enable/disable buttons, add elements to lists, change tabs). Encapsulating the _browse_ command into a System thread will allow the JavaFX thread to continue refreshing the App view, while the other thread is free to open the browser without interrupting the GUI. (Sorry for the late answer) – Pascual Lorente Arencibia Jul 24 '15 at 11:23