2015-10-13 11 views
8

ハイパーリンクがあります。クリックすると、外部のブラウザでリンクを開くことができます。JavaFx 8:アプリケーションへの参照なしにブラウザでリンクを開きます。

final Hyperlink hyperlink = new Hyperlink("http://www.google.com"); 
hyperlink.setOnAction(t -> { 
    application.getHostServices().showDocument(hyperlink.getText()); 
}); 

私はApplicationへの参照を持っていないしかし:

通常の方法は、ウェブ上で引用があると思われます。ダイアログはfxmlファイルを介して開かれているControllerから開いているので、Applicationオブジェクトへの参照を取得するのは非常に苦労します。

これを行う簡単な方法を知っている人はいますか?しかし、これはAWTスタックに依存関係を紹介することを

URI uri = ...; 
if (Desktop.isDesktopSupported()){ 
    Desktop desktop = Desktop.getDesktop(); 
    if (desktop.isSupported(Desktop.Action.BROWSE)){ 
     desktop.browse(uri); 
    } 
} 

注:

乾杯

答えて

14

解決策1:HostServicesへの参照をアプリケーションに渡します。

これはおそらく、あなたが予想している「かなり痛い」アプローチに似ています。 MainControllerで、その後

public void start(Stage primaryStage) throws Exception { 

    FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml")); 
    Parent root = loader.load(); 
    MainController controller = loader.getController(); 
    controller.setHostServices(getHostServices()); 
    primaryStage.setScene(new Scene(root)); 
    primaryStage.show(); 

} 

と::

public class DialogController { 

    @FXML 
    private Hyperlink hyperlink ; 

    private HostServices hostServices ; 

    public HostServices getHostServices() { 
     return hostServices ; 
    } 

    public void setHostServices(HostServices hostServices) { 
     this.hostServices = hostServices ; 
    } 

    @FXML 
    private void openURL() { 
     hostServices.openDocument(hyperlink.getText()); 
    } 
} 

解決方法2:

public class MainController { private HostServices hostServices ; public HostServices getHostServices() { return hostServices ; } public void setHostServices(HostServices hostServices) { this.hostServices = hostServices ; } @FXML private void showDialog() { FXMLLoader loader = new FXMLLoader(getClass().getResource("dialog.fxml")); Parent dialogRoot = loader.load(); DialogController dialogController = loader.getController(); dialogController.setHostServices(hostServices); Stage dialog = new Stage(); dialog.setScene(new Scene(dialogRoot)); dialog.show(); } } 

そしてもちろんDialogController

がどのように見える
使用しますが、基本的に、あなたのような何かをするだろうホストサービスをプッシュするコントローラファクトリコントローラに接続します。

これは、上記のよりクリーンなバージョンです。今

public class HostServicesControllerFactory implements Callback<Class<?>,Object> { 

    private final HostServices hostServices ; 

    public HostServicesControllerFactory(HostServices hostServices) { 
     this.hostServices = hostServices ; 
    } 

    @Override 
    public Object call(Class<?> type) { 
     try { 
      for (Constructor<?> c : type.getConstructors()) { 
       if (c.getParameterCount() == 1 && c.getParameterTypes()[0] == HostServices.class) { 
        return c.newInstance(hostServices) ; 
       } 
      } 
      return type.newInstance(); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

:代わりのコントローラを取得し、それらを初期化するメソッドを呼び出すと、それは、適切なコンストラクタを持っている場合、あなたは、controllerFactory経由でそれらの作成を設定し、コントローラのコンストラクタにHostServicesオブジェクトを渡すことでコントローラーを作成しますあなたはFXMLをロードする際、コントローラの工場を使用します。

public void start(Stage primaryStage) throws Exception { 
    FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml")); 
    loader.setControllerFactory(new HostServicesControllerFactory(getHostServices())); 
    Parent root = loader.load(); 
    primaryStage.setScene(new Scene(root)); 
    primaryStage.show(); 
} 

とコンストラクタのパラメータとしてHostServicesを取るために、あなたのコントローラを定義します:

public class MainController { 

    private final HostServices hostServices ; 

    public MainController(HostServices hostServices) { 
     this.hostServices = hostServices ; 
    } 

    @FXML 
    private void showDialog() { 
     FXMLLoader loader = new FXMLLoader(getClass().getResource("dialog.fxml")); 
     loader.setControllerFactory(new HostServicesControllerFactory(hostServices)); 
     Parent dialogRoot = loader.load(); 
     Stage dialog = new Stage(); 
     dialog.setScene(new Scene(dialogRoot)); 
     dialog.show(); 
    }  
} 

そしてもちろん

public class DialogController { 

    @FXML 
    private Hyperlink hyperlink ; 

    private final HostServices hostServices ; 

    public DialogController(HostServices hostServices) { 
     this.hostServices = hostServices ; 
    } 

    @FXML 
    private void openURL() { 
     hostServices.openDocument(hyperlink.getText()); 
    } 
} 

解決策3:これは無残醜いソリューションです、と私は強く、それを使用しないことをお勧めします。私はそれを含めたいと思ったので、投稿したときに他の誰かを怒らせることなく表現することができました。静的フィールドにホストサービスを格納します。

public class MainApp extends Application { 

    private static HostServices hostServices ; 

    public static HostServices getHostServices() { 
     return hostServices ; 
    } 

    public void start(Stage primaryStage) throws Exception { 

     hostServices = getHostServices(); 

     Parent root = FXMLLoader.load(getClass().getResource("main.fxml")); 
     primaryStage.setScene(new Scene(root)); 
     primaryStage.show(); 
    } 
} 

次に、あなただけのあなたが必要

MainApp.getHostServices().showDocument(hyperlink.getText()); 

のどこを行います。ここでの問題の1つは、ホストサービスにアクセスする必要があるすべてのコントローラのアプリケーションタイプに依存することです。


ソリューション4シングルトンHostServicesProviderを定義します。これは解決策3よりは優れていますが、それでもまだ良い解決策はありません。

public enum HostServicesProvider { 

    INSTANCE ; 

    private HostServices hostServices ; 
    public void init(HostServices hostServices) { 
     if (this.hostServices != null) { 
      throw new IllegalStateException("Host services already initialized"); 
     } 
     this.hostServices = hostServices ; 
    } 
    public HostServices getHostServices() { 
     if (hostServices == null) { 
      throw new IllegalStateException("Host services not initialized"); 
     } 
     return hostServices ; 
    } 
} 

は今、あなただけの依存性注入フレームワークを使用しソリューション5

public void start(Stage primaryStage) throws Exception { 
    HostServicesProvider.INSTANCE.init(getHostServices()); 
    // just load and show main app... 
} 

public class DialogController { 

    @FXML 
    private Hyperlink hyperlink ; 

    @FXML 
    private void openURL() { 
     HostServicesProvider.INSTANCE.getHostServices().showDocument(hyperlink.getText()); 
    } 
} 

を必要としています。おそらく現在のユースケースには当てはまりませんが、これらの(比較的シンプルな)フレームワークがどれほど強力であるかがわかります。

あなたがafterburner.fxを使用している場合たとえば、あなたは自分のアプリケーションstart()init()方法で

Injector.setModelOrService(HostServices.class, getHostServices()); 

を行う必要があり、その後、

public class DialogPresenter { 

    @Inject 
    private HostServices hostServices ; 

    @FXML 
    private Hyperlink hyperlink ; 

    @FXML 
    private void showURL() { 
     hostServices.showDocument(hyperlink.getText()); 
    } 
} 

春を使用した例がhereです。

+0

は醜い静的なソリ​​ューションが動作しません... getStage()と呼ばれる私のcontollerクラスのメソッドを持っていますgetStaticHostServices。私のユースケースでは最小の努力のソリューションです。 –

+0

@WolfgangFahlええ、おそらく。とにかく、私が強くお勧めするものを試してみるかどうかは分かりません。 –

+0

心配しない私は今、インターフェイスを使用しています public interface Linker { public void browse(String url); }実装を隠す - 静的なものはそのようには必要ありません –

1

もう一つの方法は、java.awt.Desktop

てみてください(未テスト)を使用することです。これは完全なJREを使用している場合は問題ではありませんが、カスタマイズされたJRE(Java SE 9 & Jigsaw)を使用したい場合、またはモバイルデバイス上でアプリケーションを実行する場合に問題になる可能性がありますjavafxports)。

今後はsupport Desktop in JavaFXに公開されている問題があります。

3

アプリ内のボタンをクリックしてfxmlコントローラファイルを使用しているときにURLを開くには、次の操作を行います。

メインアプリケーションの起動の最初のHostServicesへのポインタを取得し、ファイルオブジェクトと、そのような

stage.getProperties().put("hostServices", this.getHostServices()); 

...など、あなたのステージにそれを追加し、あなたのFXMLコントローラファイルでhostServicesは、ステージオブジェクトからオブジェクトを取得しますshowDocument()メソッドを実行します。

HostServices hostServices = (HostServices)this.getStage().getProperties().get("hostServices"); 
hostServices.showDocument("http://stackoverflow.com/"); 

私はあなたが異なっ例えばgetHostServicesに名前を付けていない場合

/** 
* @return the stage from my mainAnchor1 node. 
*/ 
public Stage getStage() { 
    if(this.stage==null) 
     this.stage = (Stage) this.mainAnchor1.getScene().getWindow(); 
    return stage; 
} 
+0

mainAnchor1とは何ですか? – simpleuser

関連する問題