2015-10-13 11 views
8

के संदर्भ के बिना ब्राउज़र में एक लिंक खोलें एक हाइपरलिंक मिला है। क्लिक किए जाने पर मैं एक बाहरी ब्राउज़र में एक लिंक खोलना चाहता हूं।जावाएफएक्स 8: एप्लिकेशन

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

हालांकि मैं Application के लिए एक संदर्भ की जरूरत नहीं है:

सामान्य विधि वेब पर उद्धृत हो रहा है। यह लिंक डायलॉग से खोला गया है, जिसे एक नियंत्रक से खोला जाता है, जिसे एक एफएक्सएमएल फ़ाइल के माध्यम से खोला जाता है, इसलिए एप्लिकेशन ऑब्जेक्ट का संदर्भ प्राप्त करना काफी दर्दनाक होगा।

क्या कोई इसे करने का एक आसान तरीका जानता है? तथापि

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

ध्यान दें कि यह AWT ढेर करने के लिए एक निर्भरता की स्थिति होगा:

चीयर्स

उत्तर

14

समाधान 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 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 की तरह लग रहा है उपयोग लेकिन मूल रूप से आप की तरह कुछ करना होगा मेजबान servic धक्का करने के लिए एक नियंत्रक कारखाना नियंत्रकों के लिए 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 उपयोग कर रहे हैं, तो आप सिर्फ अपने आवेदन 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

अगर आप getHostServices अलग तरह से जैसे नाम नहीं बदसूरत स्थिर समाधान काम नहीं करेगा getStaticHostServices। यह मेरे उपयोग के मामले में कम से कम प्रयास समाधान है। –

+0

@WolfgangFahl हाँ, शायद। निश्चित नहीं है कि आप कुछ भी कोशिश क्यों करेंगे मैं वैसे भी उपयोग करने के खिलाफ दृढ़ता से अनुशंसा करता हूं। –

+0

कोई चिंता नहीं है अब मैं एक इंटरफ़ेस का उपयोग कर रहा हूं सार्वजनिक इंटरफ़ेस लिंकर { सार्वजनिक शून्य ब्राउज़ (स्ट्रिंग यूआरएल); } जो कार्यान्वयन को छुपाता है - स्थिर सामग्री की आवश्यकता नहीं है –

1

एक और तरीका है का उपयोग करने के java.awt.Desktop

(untested) का प्रयास किया जाएगा। यदि आप पूर्ण जेआरई के साथ काम कर रहे हैं तो शायद यह कोई मुद्दा नहीं है, लेकिन यदि आप एक अनुरूप जेआरई (जावा एसई 9 & आरा) के साथ काम करना चाहते हैं तो यह एक मुद्दा बन सकता है या यदि आप मोबाइल एप्लिकेशन पर अपना एप्लिकेशन चलाने के लिए चाहते हैं (javafxports)।

भविष्य में support Desktop in JavaFX पर एक खुला मुद्दा है।

3

यदि आप अपने ऐप के अंदर एक बटन पर क्लिक करते समय यूआरएल खोलना चाहते हैं और आप एक एफएक्सएमएल नियंत्रक फ़ाइल का उपयोग कर रहे हैं तो आप निम्न कार्य कर सकते हैं ...

अपने मुख्य अनुप्रयोग स्टार्टअप फ़ाइल में सबसे पहले एक सूचक प्राप्त करने के लिए HostServices आपत्ति है और इस तरह के रूप में अपने मंच के लिए इसे जोड़ने ...

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

फिर अपने fxml नियंत्रक फ़ाइल में hostServices चरण वस्तु से वस्तु मिल और उसके बाद showDocument() विधि निष्पादित करें।

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

मैं अपने contoller getStage() कहा जाता है कक्षा में एक विधि है ...

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

मुख्य एंकर 1 क्या है? – simpleuser

संबंधित मुद्दे