JavaFX: आरंभीकरण के दौरान नियंत्रक से चरण कैसे प्राप्त करें?


91

मैं अपने कंट्रोलर क्लास से स्टेज इवेंट्स (यानी छिपाना) हैंडल करना चाहता हूं। तो मुझे बस इतना करना है कि श्रोता को इसके माध्यम से जोड़ना है

((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);

लेकिन समस्या यह है कि आरंभीकरण के ठीक बाद शुरू होता है

Parent root = FXMLLoader.load(getClass().getResource("MyGui.fxml"));

और इससे पहले कि

Scene scene = new Scene(root);
stage.setScene(scene);

इस प्रकार .getScene () शून्य हो जाता है।

मेरे द्वारा पाया गया एकमात्र हल यह है कि myPane.sceneProperty () में एक श्रोता को जोड़ा जाए, और जब यह अशक्त न हो जाए तो मुझे दृश्य मिल जाए, इसे जोड़ें। theowowProperty () my! Goddamn! श्रोता हैंडलिंग जो मैं अंत में मंच को पुनः प्राप्त करता हूं। और यह सभी घटनाओं को मंच पर वांछित श्रोताओं को स्थापित करने के साथ समाप्त होता है। मुझे लगता है कि बहुत सारे श्रोता हैं। क्या यह मेरी समस्या को हल करने का एकमात्र तरीका है?

जवाबों:


119

आप के FXMLLoaderमाध्यम से नियंत्रक के उदाहरण प्राप्त कर सकते हैं इनिशियलाइज़ेशन के माध्यम से getController(), लेकिन फिर आपको FXMLLoaderस्टैटिक विधियों का उपयोग करने के बजाय तुरंत इंस्टेंट करने की आवश्यकता है ।

मैं बाद load()में नियंत्रक को सीधे कॉल करने के बाद मंच पास करूंगा :

FXMLLoader loader = new FXMLLoader(getClass().getResource("MyGui.fxml"));
Parent root = (Parent)loader.load();
MyController controller = (MyController)loader.getController();
controller.setStageAndSetupListeners(stage); // or what you want to do

1
लगता है कि आप एक कलाकार को याद कर रहे हैं? मूल जड़ = (मूल) लोडर.लोड ();
पॉल एडेन

12
क्या यह वास्तव में ऐसा करने का सबसे अच्छा तरीका है? इसे संग्रहीत करने के लिए JavaFX फ्रेमवर्क द्वारा कुछ भी प्रदान नहीं किया गया है?
हेंस

1
किसी कारण से यह काम नहीं करता है यदि आप URL में पैरामीटर के बिना कंस्ट्रक्टर का उपयोग करते हैं और load()विधि के लिए हाथ करते हैं । (इसके अलावा, getControllerलगता है पर javadoc की तरह होना चाहिए setController।)
बोम्बे

4
@ ऐसा इसलिए है क्योंकि URL पैरामीटर के साथ लोड () विधि एक स्थिर विधि है जो उस उदाहरण पर कुछ भी सेट नहीं करती है जिसे आप इसे कॉल कर रहे हैं।
ज़ुजिक

@ सेबस्टियन, ouch, वास्तव में। मेरी गलती।
बॉम्बे

112

आपको बस AnchorPaneएक आईडी देनी है , और फिर आप उससे प्राप्त कर सकते हैं Stage

@FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();

यहां से, आप अपनी Listenerज़रूरत के अनुसार जोड़ सकते हैं ।

संपादित करें: जैसा कि नीचे EarthMind द्वारा कहा गया है, यह AnchorPaneतत्व होना जरूरी नहीं है ; यह कोई भी तत्व हो सकता है जिसे आपने परिभाषित किया है।


2
छोटा एवं सुन्दर। धन्यवाद
सेड्रिक

7
ध्यान दें कि उस विंडो में elementकोई भी तत्व हो सकता है :। उदाहरण के लिए, यदि आप केवल एक है एक साथ अपने विंडो में, का उपयोग करने वाले मंच मिलता है। fx:idStage stage = (Stage) element.getScene().getWindow();Buttonfx:id
अर्थमाइंड

29
getScene()अभी भी लौटता है null
m0skit0

3
यह जवाब है, साफ!
Destan

12
आरंभीकरण पूरा होने से पहले (उदाहरण के लिए कंट्रोलर इनिशियलाइज़ मेथड में) यह काम नहीं करेगा क्योंकि getScene () रिटर्न शून्य है। मूल पोस्टर का तात्पर्य है यह उसकी स्थिति है। इस मामले में नीचे दिए गए Utku casezdemir द्वारा दिए गए विकल्प 1 बेहतर है। यदि आपको मंच की आवश्यकता नहीं है, तो एक श्रोता पर्याप्त है, मैं इसका उपयोग इनिशियलाइज़ () में एक इमेज व्यू स्ट्रेच बनाने के लिए करता हूँ:bgimage.sceneProperty().addListener((observableScene, oldScene, newScene) -> { if (oldScene == null && newScene != null) { bgimage.fitWidthProperty().bind(newScene.widthProperty()); ... } });
जॉर्जी

32

मुझे पता है कि यह वह उत्तर नहीं है जो आप चाहते हैं, लेकिन IMO प्रस्तावित समाधान अच्छे नहीं हैं (और आपका अपना तरीका है)। क्यों? क्योंकि वे आवेदन की स्थिति पर निर्भर करते हैं। जावाएफएक्स में, एक नियंत्रण, एक दृश्य और एक मंच एक दूसरे पर निर्भर नहीं करता है। इसका मतलब है कि एक नियंत्रण एक दृश्य में जोड़े बिना रह सकता है और एक दृश्य एक मंच से जुड़े बिना हो सकता है। और फिर, एक समय में तत्काल t1, नियंत्रण एक दृश्य से जुड़ा हो सकता है और तत्काल t2 पर, उस दृश्य को एक मंच पर जोड़ा जा सकता है (और यह बताता है कि वे एक दूसरे के अवलोकन योग्य गुण क्यों हैं)।

तो वह दृष्टिकोण जो नियंत्रक संदर्भ प्राप्त करने और एक विधि को लागू करने का सुझाव देता है, इसके लिए चरण को पारित करना आपके आवेदन में एक राज्य जोड़ता है। इसका मतलब है कि आपको चरण बनाने के ठीक बाद, सही समय पर उस विधि को लागू करना होगा। दूसरे शब्दों में, आपको अब एक आदेश का पालन करने की आवश्यकता है: 1- चरण बनाएं 2- इस बनाई गई अवस्था को नियंत्रक को एक विधि के माध्यम से पास करें।

आप इस दृष्टिकोण में इस क्रम को नहीं बदल सकते (या नहीं करना चाहिए)। इसलिए तुम मूर्तिविहीन हो गए। और सॉफ्टवेयर में, आम तौर पर, राज्य बुराई है। आदर्श रूप से, तरीकों को किसी भी कॉल ऑर्डर की आवश्यकता नहीं होनी चाहिए।

तो सही समाधान क्या है? दो विकल्प हैं:

1- आपका दृष्टिकोण, नियंत्रक सुनने के गुणों में चरण पाने के लिए। मुझे लगता है कि यह सही तरीका है। इस कदर:

pane.sceneProperty().addListener((observableScene, oldScene, newScene) -> {
    if (oldScene == null && newScene != null) {
        // scene is set for the first time. Now its the time to listen stage changes.
        newScene.windowProperty().addListener((observableWindow, oldWindow, newWindow) -> {
            if (oldWindow == null && newWindow != null) {
                // stage is set. now is the right time to do whatever we need to the stage in the controller.
                ((Stage) newWindow).maximizedProperty().addListener((a, b, c) -> {
                    if (c) {
                        System.out.println("I am maximized!");
                    }
                });
            }
        });
    }
});

2- आप वही करते हैं जो आपको करने की ज़रूरत है जहाँ आप बनाते हैं Stage(और यही वह नहीं है जो आप चाहते हैं):

Stage stage = new Stage();
stage.maximizedProperty().addListener((a, b, c) -> {
            if (c) {
                System.out.println("I am maximized!");
            }
        });
stage.setScene(someScene);
...

1
यह ग्रह का सबसे छोटा जावाएफएक्स संदर्भ है !! धन्यवाद, उत्कु!
अराम पारोनिकेयन

इसे देखने का दिलचस्प तरीका। धन्यवाद :)
उत्कर्ष --zdemir

मैं एक TableView को पॉप्युलेट करने के लिए इस दृष्टिकोण का उपयोग करने की कोशिश कर रहा हूं और एक ProgressIndicator को TableView के लिए केंद्रित दिखाता हूं, लेकिन यह पता चलता है कि getX () और getY () के लिए ईवेंट मानों के अंदर वैसा ही नहीं है जैसा कि आप सभी इनिशियलाइज़ेशन के बाद उपयोग करते हैं प्रक्रिया अंत (एक बटन में एक क्लिक घटना के अंदर) या तो दृश्य और मंच के लिए, यहां तक ​​कि मंच getX () और getY () वापसी NaN, किसी भी विचार?
leobelizquierdo

@leobelizquierdo, कि इस समय getY () की समस्या है, क्या आपको एक सुस्ती मिली?
जोनासऑन

अगर मैं paneएक ऐसे दृश्य में जोड़ता हूं जो पहले से ही एक मंच से जुड़ा हुआ है, तो यह काम नहीं करेगा, सही? क्या scenePropertyश्रोता में कोई जाँच नहीं होनी चाहिए और stagePropertyयदि चरण अभी भी अशक्त है तो केवल श्रोता को जोड़ें ? अन्यथा, बस वही करो जो मुझे तुरंत करने की आवश्यकता है?
कल

14

नियंत्रक में चरण वस्तु प्राप्त करने का सबसे सरल तरीका है:

  1. अपनी बनाई गई कंट्रोलर क्लास में एक अतिरिक्त विधि जोड़ें, जैसे (यह कंट्रोलर क्लास में स्टेज सेट करने के लिए एक सेटर विधि होगी),

    private Stage myStage;
    public void setStage(Stage stage) {
         myStage = stage;
    }
    
  2. प्रारंभ विधि और सेट चरण में नियंत्रक प्राप्त करें

    FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
    OwnController controller = loader.getController();
    controller.setStage(this.stage);
    
  3. अब आप नियंत्रक में चरण तक पहुंच सकते हैं


यह मेरे लिए विजेता था। रॉबर्ट मार्टिन के जवाब ने पहले काम किया, लेकिन फिर एक त्रुटि फेंकना शुरू कर दिया, जिसे मैंने stageइस तरह से हल किया ।
दाममूल

1

Fx असाइन करें : आईडी या किसी भी नोड के / के लिए चर घोषित: anchorpane, बटन, आदि। फिर इसमें इवेंट हैंडलर जोड़ें और उस ईवेंट हैंडलर के नीचे दिए गए कोड डालें:

Stage stage = (Stage)((Node)((EventObject) eventVariable).getSource()).getScene().getWindow();

उम्मीद है इससे आपका काम बनेगा!!


1

प्लेटफ़ॉर्म। क्रूनलेटर आरंभिक पूर्ण होने तक निष्पादन को रोकने के लिए काम करता है। इस मामले में, मैं हर बार खिड़की की चौड़ाई का आकार बदलने के लिए एक सूची दृश्य ताज़ा करना चाहता हूं।

Platform.runLater(() -> {
    ((Stage) listView.getScene().getWindow()).widthProperty().addListener((obs, oldVal, newVal) -> {
        listView.refresh();
    });
});

आपके मामले में

Platform.runLater(()->{
    ((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
});

-3

node.getSceneयदि आप से कॉल नहीं करते हैं, तो आप प्राप्त कर सकते हैं , Platform.runLaterपरिणाम एक अशक्त मूल्य है।

उदाहरण शून्य मान:

node.getScene();

उदाहरण कोई शून्य मान:

Platform.runLater(() -> {
    node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
               //your event
     });
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.