解決方案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:使用一個控制器工廠推動主機服務es到控制器。
這是上述清潔版本。相反,越來越控制器並調用一個方法來初始化它們,你通過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更好,但仍不是一個好的解決方案。
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的一個例子是here。
如果你不命名getHostServices例如不同的醜惡靜態解決方案將無法正常工作getStaticHostServices。這是我用例中最省力的解決方案。 –
@WolfgangFahl是的,可能。不知道爲什麼你甚至會嘗試我強烈建議不要使用的東西。 –
不用擔心我現在正在使用一個接口 public interface Linker {0} {0} {0} public void browse(String url); } 其中隱藏了實現 - 靜態東西不需要那種方式 –