2016-03-20 6 views
0

я узнавал JavaFX этого день, и я застрял на этой ошибке здесь:Связь между контроллерами и FXML файлами на разных этапах

я создаю простую игру, как Tribal Wars/Битвы Кланов. Мой вопрос здесь в том, как я могу отправить информацию с одного этапа (window/confirmSerra.fxml/Controller2.java) на другой этап (primarystage/aldeiaPage.fxml/aldeiaControl.java), который уже создан и запущен.

Я уже знаю, как отправлять информацию с одного этапа на другой, если он еще не создан.

Это мой Main.java, запускающий principalStage игры:

public class Main extends Application { 


    @Override 
    public void start(Stage primaryStage) throws Exception{ 

     FXMLLoader fxmlLoader = new FXMLLoader(); 
     fxmlLoader.setLocation(getClass().getResource("aldeiaPage.fxml")); 
     Parent root = fxmlLoader.load(); 

     primaryStage.setTitle("Jogo_Alpha - Aldeia"); 
     primaryStage.setScene(new Scene(root, 1024, 768)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 

     launch(args); 
    } 
} 

Это какая-то часть контроллера "aldeiaControl.java" от "aldeiaPage.fxml":

@FXML public void teste1() throws Exception { 

    Stage window = new Stage(); 
    FXMLLoader fxmlLoader = new FXMLLoader(); 
    fxmlLoader.setLocation(getClass().getResource("confirmSerra.fxml")); 

    Pane layout = fxmlLoader.load(); 
    Scene scene = new Scene(layout); 

    Controller2 c = fxmlLoader.getController(); 
    window.setTitle("Upgrade Serralheria"); 

    window.setScene(scene); 
    window.show(); 

    c.labelserraLev.setText(String.valueOf(seralevelNum)); 
    //seralevelNum is a variable from this controller "aldeiaControl" 
} 

Как вы можете видеть, я могу создать новый этап из кнопки clicke test1, которая связана с файлом @FXML. И сделав это FXMLLoader и .getController(), дайте мне доступ к labelserraLev, который находится в другом контроллере.

Controller2.java

public class Controller2 { 


    @FXML public Label labelserraLev; 


    @FXML public void buttonclick() throws Exception { 

     FXMLLoader fxmlLoader = new FXMLLoader(); 
     fxmlLoader.load(getClass().getResource("aldeiaPage.fxml")); 

     aldeiaControl labelchange = fxmlLoader.getController(); 

     labelchange.seralevel.setText("10"); 

    } 

} 

Как я могу изменить текст метки в principalstage (который был уже создан и работает до сих пор), когда я нажимаю эту buttonclick() (то есть кнопка обновления на фото ниже)? Я мог бы изменить текст метки нового окна, но поскольку это было новое окно, но о уже созданном окне, я не могу.

Ошибка заключается в следующем:

Caused by: java.lang.NullPointerException 
at sample.Controller2.buttonclick(Controller2.java:30) 

enter image description here

ответ

1

Это вообще плохая практика, чтобы выставить компоненты пользовательского интерфейса вне классов контроллеров: это в основном ломается инкапсуляцию. Я бы пошел дальше и предположил, что в большинстве случаев вашим контроллерам также не нужны ссылки друг на друга.

FXML - это «Вид», а класс контроллера состоит из двух частей (довольно слабо определенного) шаблона проектирования, называемого «Model-View-Controller». Модель, которую вы здесь не видите, - это модель. В некоторых вариантах контроллер заменяется презентатором, и, возможно, «контроллер», прикрепленный к файлу FXML, больше похож на презентатора.

Основная идея заключается в том, что модель хранит данные: представление представляет данные пользователю, а контроллер обрабатывает ввод пользователя и обновляет модель в ответ. В некоторых версиях шаблона контроллер/презентатор наблюдает за данными в модели и обновляет представление при его изменении. (В других случаях, вид наблюдает за моделью и обновляется при изменении данных.)

Преимущество этой конструкции заключается в том, что вы можете иметь несколько видов одних и тех же данных, которые могут оставаться синхронизированными, не зная друг о друге. Все пары view/presenter наблюдают данные в модели, поэтому, если один из ведущих обновляет модель, все просмотры обновляются с помощью наблюдения.

Так что вам нужен класс модели, который содержит данные:

public class Model { 

    private final IntegerProperty level = new SimpleIntegerProperty(); 

    public IntegerProperty levelProperty() { 
     return level ; 
    } 

    public final int getLevel() { 
     return levelProperty().get(); 
    } 

    public final void setLevel(int level) { 
     levelProperty().set(level); 
    } 

    // other properties etc... 
} 

Теперь контроллеры нужно ссылку на модель, и связать их взгляды на него:

public class AldeiaControl { 

    private Model model ; 

    @FXML 
    private Label seraLevel ; 

    public void setModel(Model model) { 
     this.model = model ; 
     seraLevel.textProperty().bind(model.levelProperty().asString()); 
    } 

    @FXML public void teste1() throws Exception { 

     Stage window = new Stage(); 
     FXMLLoader fxmlLoader = new FXMLLoader(); 
     fxmlLoader.setLocation(getClass().getResource("confirmSerra.fxml")); 

     Pane layout = fxmlLoader.load(); 
     Scene scene = new Scene(layout); 

     Controller2 c = fxmlLoader.getController(); 
     window.setTitle("Upgrade Serralheria"); 

     window.setScene(scene); 
     window.show(); 

     c.setModel(model); 
    } 

} 

и

public class Controller2 { 


    @FXML private Label labelserraLev; 

    private Model model ; 

    public void setModel(Model model) { 
     this.model = model ; 
     labelserraLev.textProperty().bind(model.levelProperty().asString()); 
    } 

    @FXML public void buttonclick() throws Exception { 

     // will automatically update all properties bound to the model's level: 
     model.setLevel(10); 

    } 

} 

Наконец, создайте модель и передайте ее контроллеру:

public class Main extends Application { 


    @Override 
    public void start(Stage primaryStage) throws Exception{ 

     Model model = new Model(); 

     FXMLLoader fxmlLoader = new FXMLLoader(); 
     fxmlLoader.setLocation(getClass().getResource("aldeiaPage.fxml")); 
     Parent root = fxmlLoader.load(); 

     AldeiaControl controller = fxmlLoader.getController(); 
     controller.setModel(model); 

     primaryStage.setTitle("Jogo_Alpha - Aldeia"); 
     primaryStage.setScene(new Scene(root, 1024, 768)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 

     launch(args); 
    } 
} 

Также см Applying MVC With JavaFx

+0

Гай, я попытался скопировать эти коды у меня дали, так что я мог видеть, как это будет работать здесь, у меня появилась идея, но я пытался увидеть его работы. Я скопировал код в свои файлы и скорректировал файл fxml, но теперь у меня есть 2 erros. Что мне не хватает? Исключение в потоке "основного" java.lang.RuntimeException: Исключение в применении метода запуска вызвано следующими причинами: java.lang.NullPointerException \t на sample.AldeiaControl.setModel (AldeiaControl.java:24) \t в sample.Main. start (Main.java:23) – Brancol

+0

Наверное, только, чтобы метка была нулевой. Вы не дали полного примера для работы с ... Я бы просто проверил, что 'fx: id' на ярлыке соответствует имени поля. –

+0

Нет, это соответствует <Ярлык fx: id = "seralevel" prefHeight = "34.0" prefWidth = "76.0" text = "startLevel" /> Прошу прощения за это, если вы хотите увидеть полный код u можете его получить http://www.mediafire.com/download/1jgcb3072n8dzs8/jogoAlpha.rar У этого уже есть изменения, сделанные – Brancol