有一个超链接。单击后,我希望在外部浏览器中打开链接。
网络上引用的常用方法似乎是:
final Hyperlink hyperlink = new Hyperlink("http://www.google.com");
hyperlink.setOnAction(t -> {
application.getHostServices().showDocument(hyperlink.getText());
});
但是我没有提及Application
。该链接是从对话框打开的,该对话框是从控制器打开的,而该对话框是通过fxml文件打开的,因此获得对Application对象的引用将非常痛苦。
有人知道这样做的简单方法吗?
干杯
解决方案1:HostServices
通过您的应用程序向下传递引用。
这可能类似于您预期的“非常痛苦”的方法。但基本上,您会执行以下操作:
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();
}
然后在MainController
:
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 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: 使用控制器工厂将主机服务推送到控制器。
这是上面的更干净的版本。您无需通过获取控制器并调用方法来对其进行初始化,而是通过a来配置它们的创建,并通过controllerFactory
将一个HostServices
对象传递给控制器的构造函数(如果它具有合适的构造函数)来创建控制器:
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);
}
}
}
现在,在加载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());
您需要的任何地方。这里的问题之一是,您为需要访问主机服务的所有控制器引入了对应用程序类型的依赖。
解决方案4 定义一个单例HostServicesProvider
。这比解决方案3更好,但仍然不是imo的好解决方案。
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 ;
}
}
现在你只需要
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());
}
}
解决方案5 使用依赖项注入框架。这可能不适用于您当前的用例,但可能会让您了解这些(相对简单的)框架的功能。
例如,如果您使用afterburner.fx,则只需执行以下操作
Injector.setModelOrService(HostServices.class, getHostServices());
在您的应用程序start()
或init()
方法中,然后
public class DialogPresenter {
@Inject
private HostServices hostServices ;
@FXML
private Hyperlink hyperlink ;
@FXML
private void showURL() {
hostServices.showDocument(hyperlink.getText());
}
}
这里有一个使用Spring的例子。
我在我的应用程序中启用了应用链接。它工作正常。但是在我的应用程序中,有一些情况下我无法处理传入的网址。在这种情况下,我想将该网址重定向到设备中的默认浏览器。 目前,我尝试使用intent打开带有url的浏览器,但它再次重定向到我的应用程序本身。应用程序链接的格式如下- 所以根据params,我想要么在应用程序本身中处理应用程序链接,要么将其重定向到默认浏览器。下面是我试图用上面的网址打开浏览器的代
从这篇文章中,我能够创建一个功能,将用户从一个链接重定向到android或ios。但是,在检测到Android时,我想打开显示我的应用程序的游戏商店。我在重定向时尝试了以下链接: 但它会在浏览器中打开play store。我想打开play store应用程序,我假设我的应用程序用户将使用play store应用程序,所以我不想检查play store应用程序是否已安装。我也尝试了如下的市场链接 但
我已将AssetLink文件托管到我们的域中https://ourdomain/.well-known/assetlinks.json并用计算机进行了验证https://developers.google.com/digital-asset-links/tools/generator通过android studio的应用程序链接Assistant,并通过两种方式获得验证状态。但当我共享调试APK进
我有一个非常简单的测试应用程序,上面有一个webview组件。我正试图阻止链接在浏览器中打开,但“shouldoverrideurlloading”看起来对我不起作用。 有人能帮我看看哪里有错误吗?
我最近实现了shouldInterceptRequest方法来检测链接的时间“http://sitemercado.com.br/valida“点击在android浏览器中打开它,而不是在webview中内部打开,直到它工作为止。链接在浏览器中打开,但当我回来查看webview应用程序时,它也被加载了,我希望它只在浏览器中加载。 我的代码如下: 我哪里做错了?
问题内容: 是否有任何(简单/内置方式)打开新浏览器(我的意思是默认的OS浏览器)窗口来查找Electron链接的方法,而不是访问您Electron应用程序中的链接? 问题答案: 您可以简单地使用: