• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Jak użyć konstruktora w kontrolerze

0 głosów
307 wizyt
pytanie zadane 25 stycznia 2017 w Java przez Jonki Dyskutant (8,190 p.)

Witam. Mam oto taki mały problem. Potrzebuję w klasie kontrolera zbindować pewne pola tekstowe z danymi obiektu. Wygląda to tak.


Pobieram formatkę:

public void loadChangeNameAndLastName(Person person) {
        FXMLLoader loader = LoadFXML.loadFXML(getClass(), FXML_CHANGE_NAME_AND_LAST_NAME);
 
        Node node = null;
        try {
            node = loader.load();
        } catch(IOException e) {
            e.printStackTrace();
        }
 
        serviceWindowController.setCenter((Pane)node);
    }

kontrolerem dla tej formatki jest ChangeNameAndLastNameController, więc tworzę w klasie obiekt Person. W tej sytuacji musiałbym w jakiś sposób użyć konstruktora, ale nie da rady ot tak stworzyć obiektu, bo kontroler połączony jest z tą formatką FXML.

Można próbować tak:

ChangeNameAndLastNameController changeNameAndLastNameController = loader.getController();
changeNameAndLastNameController.setPerson(person);

ale wtedy w metodzie '@Override public void initialize()' nie można zbindować tego obiektu z polem tekstowym, bo ta metoda wywoływana jest podczas jeszcze samego tworzenia obiektu, a ja ten obiekt 'person' przesyłam po utworzeniu obiektu. Chcę po prostu przesłać jakoś do kontrolera obiekt i jego pole zbindować w metodzie 'initialize()' z polem tekstowym formatki.

1 odpowiedź

+1 głos
odpowiedź 26 stycznia 2017 przez K0XM4N Gaduła (3,640 p.)
wybrane 26 stycznia 2017 przez Jonki
 
Najlepsza

Hej, też miałem z tym problemy. Musisz to zrobić w kodzie, który będzie to okno zmieniał/wyświetlał nowe.

Najpierw tworzysz obiekt FXMLloadera, i ustawiasz lokalizacje do pliku FXML:
 

FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(pathToViewFXML));

Potem żeby coś przesłać do kontrolera, korzystając z loadera, ładujesz hierarchię obiektów z pliku FXML do obiektu Node czy klas pochodnych takich jak Parent, Pane, VBox, Hbox, BorderPane etc.
 

container = loader.load();

W moim przypadku to był akurat VBox, ale nie ma to znaczenia
Dopiero teraz wyciągasz z loadera controller pliku FXML:

ChatController chatController = loader.getController();

Mając wcześniej zdefiniowane pola w kontrolerze, w moim przypadku będzie to String textToSet, a może to tez być obiekt Person, ustawiasz tą zmienną poprzez setter, a w kolejnej metodzie wykonujesz operacje wykorzystując ten obiekt. Nie ma potrzeby korzystania z metody Initialize w kontrolerze!

chatController.setTemporaryText("trololololo");
chatController.setTextOnChatArea();


I w dalszej części albo tworzysz nowe okno, poprzez utworzenie nowej sceny, dodanie do sceny Obiektu Node(Parent, VBox, Pane etc), utworzenie Stage i przekazanie do niego sceny, a następnie wyświetlenie okienka Stage np.:

        Scene scene = new Scene(container);
        Stage window = new Stage();
        window.setScene(scene);
        window.show();

Lub dodanie wszystkich elementów hierarchii FXML do akutalnego kontera, po uprzednim jego wyczyszczeniu:
 

    public void show(VBox currentVBoxContainer, VBox changedContainer){

        currentVBoxContainer.getChildren().clear();
        currentVBoxContainer.setVgrow(changedContainer,Priority.ALWAYS); // nie jest wymagane
        currentVBoxContainer.getChildren().addAll(changedContainer);

    }


Moja klasa odpowiadająca za zmianę sceny ( z dodatkowymi przykładami :P)

 

public class SceneSwitcherModel {

    private VBox container;

    public VBox loadScreen(String pathToViewFXML) throws IOException {

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource(pathToViewFXML));

        container = loader.load();

        ChatController chatController = loader.getController();
        chatController.setTemporaryText("trololololo");
        chatController.setTextOnChatArea();

        return container;
    }

    public void show(VBox currentVBoxContainer, VBox changedContainer){

        currentVBoxContainer.getChildren().clear();
        currentVBoxContainer.setVgrow(changedContainer,Priority.ALWAYS);
        currentVBoxContainer.getChildren().addAll(changedContainer);

    }
}


Jest jeszcze kilka innych sposobów, np poprzez wykorzystanie Singletona, ale to tylko w odpowiedniej sytuacji. Wtedy w metodzie initialize, możesz pobrać instancje obiektu, który jest singletonem i dzięki temu obiektowi (wykorzystując pola tego obiektu etc) coś zmieniać na formatce.

Mam nadzieję, że pomogłem, jeśli tak zostaw najlepszą odpowiedź! :D W razie czego pisz :)

komentarz 26 stycznia 2017 przez Jonki Dyskutant (8,190 p.)
edycja 26 stycznia 2017 przez Jonki
Właśnie wczoraj wieczorem doszedłem do tego drugiego sposobu, ale poprzez metodę statyczną, bo wzorzec projektowy Singleton dla klasy 'Person' nie działał by odpowiednio, bo piszę coś na wzór serwisu społecznościowego i  każdy użytkownik będzie robiony według tej klasy. Ale ten pierwszy, który podałeś jest lepszy, prosty i piękny. Stworzę metodę w kontrolerze bindPerson() i tam zrobię to bindowanie. Dzięki. Pomogło.
komentarz 26 stycznia 2017 przez K0XM4N Gaduła (3,640 p.)
Spoko :) A uporałeś się z zmianą rozmiaru komponentów :P?
komentarz 26 stycznia 2017 przez Jonki Dyskutant (8,190 p.)
W pewnym sensie tak. Stworzył kontener VBox, który umieściłem w AnchorPane. Więc gdy aplikacja była w małym oknie, to wyglądało OK, ale gdy okno powiększało się w wysokości tylko do około końca lewego panelu. Po prostu ten kontener wymuszał zachowanie proporcji, przez co nie mogłem osiągnąć takiego efektu jak chciałem. O tyle dobra była możliwość zbindowania 'styleProperty()' kontenera z rozmiarem okna aplikacji i automatyczne zmienianie 'font size' wszystkich elementów w CSS. Problem był również taki, że podczas powiększania okna, rozjeżdżały się kontrolki label i np. textField, bo textField ma większy padding niż label, przez co szybciej zmieniał położenie. No ale jak napisałem wcześniej, nie do końca ten kontener mi odpowiadał więc zamieniłem go na GridPane. Kontener ładnie rozciąga się we wszystkie strony. Jeden minus to taki, ze nie można zbindować 'styleProperty()'. Po prostu brak efektu, ale potem jakoś to załatwię. Ale koniec końców efekt jest bardzo dobry i taki zostawie. Małe okno: https://zapodaj.net/67fa151585bcf.png.html https://zapodaj.net/bab3566a5ada8.png.html Duże okno: https://zapodaj.net/7590a1721d28d.png.html A jak komuś nie będzie odpowiadał taki układ przy powiększeniu, to w ustawieniach jest możliwość zablokowanie zmieniania rozmiaru okna. https://zapodaj.net/0e1fa75a34547.png.html

 

PS: W poprzednik wątku chyba źle wytłumaczyłem problem. Nie chodziło mi o lewy panel, tylko ten środkowy. A ta zakładka na lewym panelu to 'TitledPane' umieszczony w kontenerze Accordion.
komentarz 28 stycznia 2017 przez K0XM4N Gaduła (3,640 p.)
Musiałbyś umieścić VBox jako główny kontener dla wszystkich innych komponentów. Mimo to całkiem spoko to wygląda. Front-end dobry :D. Ja jeszcze nie bawiłem się w podpinanie CSSa pod javaFX'a ale na pewno to zrobie gdy dokończe back-end mojej apki :P

Podobne pytania

0 głosów
0 odpowiedzi 78 wizyt
pytanie zadane 26 stycznia 2017 w Java przez Jonki Dyskutant (8,190 p.)
0 głosów
2 odpowiedzi 197 wizyt
0 głosów
1 odpowiedź 120 wizyt

88,677 zapytań

137,288 odpowiedzi

306,652 komentarzy

58,873 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Sklep oferujący ćwiczenia JavaScript, PHP, rozmowy rekrutacyjne dla programistów i inne materiały

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...