简体   繁体   中英

Open External Application From JavaFX

I found a way to open a link on default browser using HostServices.

getHostServices().showDocument("http://www.google.com");
  • Is there any way to open a media in default media player?
  • Is there any way to launch a specific File or Application ?

Generally speaking, you can use Desktop#open(file) to open a file natively as next:

final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if (desktop != null && desktop.isSupported(Desktop.Action.OPEN)) {
    desktop.open(file);
} else {
    throw new UnsupportedOperationException("Open action not supported");
}

Launches the associated application to open the file. If the specified file is a directory, the file manager of the current platform is launched to open it.

More specifically, in case of a browser you can use directly Desktop#browse(uri) , as next:

final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
    desktop.browse(uri);
} else {
    throw new UnsupportedOperationException("Browse action not supported");
}

Launches the default browser to display a URI . If the default browser is not able to handle the specified URI , the application registered for handling URIs of the specified type is invoked. The application is determined from the protocol and path of the URI , as defined by the URI class. If the calling thread does not have the necessary permissions, and this is invoked from within an applet, AppletContext.showDocument() is used. Similarly, if the calling does not have the necessary permissions, and this is invoked from within a Java Web Started application, BasicService.showDocument() is used.

If you want to either open a URL which has an http: scheme in the browser, or open a file using the default application for that file type, the HostServices.showDocument(...) method you referenced provides a "pure JavaFX" way to do this. Note that you can't use this (as far as I can tell) to download a file from a web server and open it with the default application.

To open a file with the default application, you must convert the file to the string representation of the file: URL. Here is a simple example:

import java.io.File;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class OpenResourceNatively extends Application {

    @Override
    public void start(Stage primaryStage) {
        TextField textField = new TextField("http://stackoverflow.com/questions/39898704");
        Button openURLButton = new Button("Open URL");
        EventHandler<ActionEvent> handler = e -> open(textField.getText());
        textField.setOnAction(handler);
        openURLButton.setOnAction(handler);

        FileChooser fileChooser = new FileChooser();
        Button openFileButton = new Button("Open File...");
        openFileButton.setOnAction(e -> {
            File file = fileChooser.showOpenDialog(primaryStage);
            if (file != null) {
                open(file.toURI().toString());
            }
        });

        VBox root = new VBox(5, 
                new HBox(new Label("URL:"), textField, openURLButton),
                new HBox(openFileButton)
        );

        root.setPadding(new Insets(20));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    private void open(String resource) {
        getHostServices().showDocument(resource);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Only the solution with java.awt.Desktop worked for me to open a file from JavaFX.

However, at first, my application got stuck and I had to figure out that it is necessary to call Desktop#open(File file) from a new thread. Calling the method from the current thread or the JavaFX application thread Platform#runLater(Runnable runnable) resulted in the application to hang indefinitely without an exception being thrown.

This is a small sample JavaFX application with the working file open solution:

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class FileOpenDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        final Button button = new Button("Open file");

        button.setOnAction(event -> {
            final FileChooser fileChooser = new FileChooser();
            final File file = fileChooser.showOpenDialog(primaryStage.getOwner());

            if (file == null)
                return;

            System.out.println("File selected: " + file.getName());

            if (!Desktop.isDesktopSupported()) {
                System.out.println("Desktop not supported");
                return;
            }

            if (!Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
                System.out.println("File opening not supported");
                return;
            }

            final Task<Void> task = new Task<Void>() {
                @Override
                public Void call() throws Exception {
                    try {
                        Desktop.getDesktop().open(file);
                    } catch (IOException e) {
                        System.err.println(e.toString());
                    }
                    return null;
                }
            };

            final Thread thread = new Thread(task);
            thread.setDaemon(true);
            thread.start();
        });

        primaryStage.setScene(new Scene(button));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

The other proposed solution with javafx.application.HostServices did not work at all. I am using OpenJFX 8u141 on Ubuntu 17.10 amd64 and I got the following exception when invoking HostServices#showDocument(String uri) :

java.lang.ClassNotFoundException: com.sun.deploy.uitoolkit.impl.fx.HostServicesFactory

Obviously, JavaFX HostServices is not yet properly implemented on all platforms. On this topic see also: https://github.com/Qabel/qabel-desktop/issues/420

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM