Lösung 1: Übergeben Sie einen Verweis auf die HostServices
nach unten durch Ihre Anwendung.
Dies ist wahrscheinlich ähnlich dem "ziemlich schmerzhaften" Ansatz, den Sie erwarten. Aber im Grunde würden Sie so etwas wie:
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();
}
und dann in 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();
}
}
und natürlich DialogController
wie folgt aussieht:
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());
}
}
Lösung 2: Verwenden eine Controller-Fabrik, um den Host-Dienst zu drücken es zu den Controllern.
Dies ist eine sauberere Version des oben genannten.Statt die Controller des Erhaltens und Aufrufen einer Methode, sie zu initialisieren, konfigurieren Sie die Erstellung von ihnen über einen controllerFactory
und Controller erstellen, indem ein HostServices
Objekt an den Konstruktor der Controller vorbei, wenn es einen geeigneten Konstruktor hat:
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);
}
}
}
Jetzt verwenden Sie die Controller Factory, wenn Sie die FXML laden:
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();
}
und definieren Sie Ihre Controller HostServices
als Konstrukteur Parameter zu übernehmen:
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();
}
}
und natürlich
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());
}
}
Lösung 3:Dies ist eine kläglich hässliche Lösung, und ich gegen die Verwendung es nur sehr empfehlen. Ich wollte es nur hinzufügen, damit ich das ausdrücken konnte, ohne jemand anderen zu beleidigen, wenn sie es gepostet haben. Speichern Sie die Host-Services in einem statischen Feld.
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();
}
}
Dann tun Sie gerade
MainApp.getHostServices().showDocument(hyperlink.getText());
überall Sie benötigen. Eines der Probleme besteht darin, dass Sie für alle Controller, die Zugriff auf die Host-Services benötigen, eine Abhängigkeit von Ihrem Anwendungstyp einführen.
Lösung 4 Definieren eines Singletons HostServicesProvider
. Das ist besser als Lösung 3, aber immer noch keine gute Lösung 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 ;
}
}
Jetzt müssen Sie nur
public void start(Stage primaryStage) throws Exception {
HostServicesProvider.INSTANCE.init(getHostServices());
// just load and show main app...
}
und
public class DialogController {
@FXML
private Hyperlink hyperlink ;
@FXML
private void openURL() {
HostServicesProvider.INSTANCE.getHostServices().showDocument(hyperlink.getText());
}
}
Lösung 5 ein Dependency Injection-Framework verwenden. Dies trifft wahrscheinlich nicht auf Ihren aktuellen Anwendungsfall zu, könnte Ihnen aber eine Vorstellung davon geben, wie mächtig diese (relativ einfachen) Frameworks sein können.
Zum Beispiel, wenn Sie afterburner.fx verwenden, müssen Sie nur
Injector.setModelOrService(HostServices.class, getHostServices());
in Ihrer Anwendung start()
oder init()
Methode zu tun, und dann
public class DialogPresenter {
@Inject
private HostServices hostServices ;
@FXML
private Hyperlink hyperlink ;
@FXML
private void showURL() {
hostServices.showDocument(hyperlink.getText());
}
}
Ein Beispiel Frühling ist mit here.
die hässliche statische Lösung wird nicht funktionieren, wenn Sie das getHostServices nicht anders nennen z.B. getStaticHostServices. Es ist die Lösung mit dem geringsten Aufwand in meinem Anwendungsfall. –
@WolfgangFahl Ja, wahrscheinlich. Ich bin mir nicht sicher, warum Sie überhaupt etwas versuchen sollten, das ich so dringend davon abraten kann, es trotzdem zu benutzen. –
keine Sorgen, ich benutze jetzt eine Schnittstelle öffentliche Schnittstelle Linker { öffentlichen leeren Durchsuchen (String URL); } was verbirgt die Implementierung - das statische Zeug ist nicht auf diese Weise benötigt –