JavaFX: 2 независимых окна одновременно

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

0
задан iCV 13 April 2019 в 18:45
поделиться

2 ответа

Ниже приведена демонстрация двух окон (этапов), использующих одну и ту же модель.
Демонстрация максимально проста: в одном окне отображается список. Второе окно динамически отображает элементы, которые были выбраны в первом:

enter image description here

Совместно используемая модель содержит информацию, которая нужна двум окнам. В основном список элементов и список выбранных элементов:

package two_windows;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Model {

    private final ObservableList<String> list;
    private ObservableList<String> selected;

    Model(){
        list = FXCollections.observableArrayList();
    }

    void addMessage(String msg){
        list.add(msg);
    }

    ObservableList<String> getMessages(){
        return list;
    }

    ObservableList<String> getSelectedMessages(){
        return selected;
    }

    void setSelected(ObservableList<String> selected) {
        this.selected = selected;
    }
}

Содержимое первого окна определяется List.fxml и его контроллером:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>

<Pane xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1"
 fx:controller="two_windows.ListController">
   <children>
        <ListView fx:id="list" prefHeight="300.0" prefWidth="150.0" />
    </children>
</Pane>

Контроллер принимает Model, устанавливает список выбранных элементов в модели, слушает и реагирует на изменения модели:

package two_windows;

import java.util.List;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;

public class ListController {

    @FXML ListView<String> list;

    void setModel(Model model) {

        list.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);//allow multiple selection

        //sets the selected items of the list to the model 
        model.setSelected(list.getSelectionModel().getSelectedItems());

        //listen to changes in model, and respond
        model.getMessages().addListener(
                                        (ListChangeListener<String>) c -> {
                                            c.next();
                                            addElements(c.getAddedSubList());
                                        }
                                    );
    }

    private void addElements(List<? extends String> msgList){

        for(String msg : msgList){
            list.getItems().add(msg);
        }
    }
}

Содержимое второго окна очень похоже на первое, и определяется Selected.fxml :

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>  

<Pane xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1"
 fx:controller="two_windows.SelectedController">
   <children>
        <ListView fx:id="selected" prefHeight="300.0" prefWidth="150.0" />
    </children>
</Pane>

И его контроллер, который, как и другой контроллер, принимает Model и реагирует на изменения в нем:

package two_windows;

import java.util.List;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;

public class SelectedController {

    @FXML ListView<String> selected;

    void setModel(Model model) {

        //listen to changes in model, and respond
        model.getSelectedMessages().addListener(
                    (ListChangeListener<String>) c -> {
                        c.next();
                        removeElements(c.getRemoved());
                        addElements(c.getAddedSubList());
                    }
                );
    }

    private void removeElements(List<? extends String> msgList){

        for(String msg : msgList){
            selected.getItems().remove(msg);
        }
    }

    private void addElements(List<? extends String> msgList){

        for(String msg : msgList){
            selected.getItems().add(msg);
        }
    }
}
[ 1118] Собираем все вместе и тестируем:

package two_windows;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class TwoWindows extends Application {

    private Model model;

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

        model = new Model();

        FXMLLoader listLoader = new FXMLLoader(getClass().getResource("List.fxml"));
        Parent list = listLoader.load();
        ListController listController = listLoader.getController();
        listController.setModel(model);

        FXMLLoader selectedLoader = new FXMLLoader(getClass().getResource("Selected.fxml"));
        Parent selected = selectedLoader.load();
        SelectedController selectedController = selectedLoader.getController();
        selectedController.setModel(model);

        primaryStage.setScene(new Scene(list));
        primaryStage.setX(350); primaryStage.setY(300);

        Stage secondaryStage = new Stage();
        secondaryStage.setScene(new Scene(selected));
        secondaryStage.setX(550); secondaryStage.setY(300);

        addMessages();
        primaryStage.show();
        secondaryStage.show();
    }

    private void addMessages() {

        int counter = 0;
        while(counter < 15) {
            model.addMessage("message number "+ counter++);
        }
    }

    public static void main(final String[] args) {
        launch(args);
    }
}
0
ответ дан c0der 13 April 2019 в 18:45
поделиться

В основном необходимо следовать @Slaw инструкциям. Создайте Model. Совместно используйте Model между два Controllers. Наблюдайте ток модели Customer и реагируйте соответственно. MCVE Ниже:

Основной Класс: (загружают оба этапа корректной Сценой. Создайте модель и передайте ее обоим Контроллерам):

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author sedri
 */
public class JavaFXApplication36 extends Application {

    @Override
    public void start(Stage stage) {
        try {
            FXMLLoader listViewFXMLLoader = new FXMLLoader(getClass().getResource("ListViewFXML.fxml"));
            Parent listViewRoot = listViewFXMLLoader.load();
            ListViewController listViewController = listViewFXMLLoader.getController();
            Scene scene1 = new Scene(listViewRoot);
            stage.setScene(scene1);           

            FXMLLoader detailsFXMLLoader = new FXMLLoader(getClass().getResource("DetailsFXML.fxml"));
            Parent detailsRoot = detailsFXMLLoader.load();
            DetailsController detailsController = detailsFXMLLoader.getController();
            Scene scene2 = new Scene(detailsRoot);
            Stage stage2 = new Stage();
            stage2.setScene(scene2);

            DataModel model = new DataModel();
            listViewController.initModel(model);
            detailsController.initModel(model);

            stage.show();
            stage2.show(); 
        } catch (IOException ex) {
            Logger.getLogger(JavaFXApplication36.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Образцовый Класс: (Не отстают от текущего Клиента и ObservableList Клиента)

import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
 *
 * @author sedrick
 */
public class DataModel {
    private final ObservableList<Customer> customerList = FXCollections.observableArrayList(customer -> new Observable[]{customer.nameProperty(), customer.ageProperty()});
    private final ObjectProperty<Customer> currentCustomer = new SimpleObjectProperty();

    public ObjectProperty<Customer> currentCustomerProperty() {
        return currentCustomer;
    }

    public void setCurrentCustomer(Customer currentCustomer) {
        this.currentCustomer.set(currentCustomer);
    }

    public Customer getCurrentCustomer() {
        return this.currentCustomer.get();
    }  


    public ObservableList<Customer> loadCustomers()
    {        
        customerList.add(new Customer("John Doe", 21));
        customerList.add(new Customer("Jane Joe", 20));

        return customerList;
    }
}

Клиентский Класс:

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
 *
 * @author sedrick
 */
public class Customer {
    private final StringProperty name = new SimpleStringProperty();
    private final IntegerProperty age = new SimpleIntegerProperty();
    public Customer(String name, int age) {
        this.name.set(name);
        this.age.set(age);
    }

    public String getName()
    {
       return this.name.get();
    }

    public void setName(String name)
    {
        this.name.set(name);
    }

    public StringProperty nameProperty()
    {
        return this.name;
    }

    public int getAge()
    {
       return this.age.get();
    }

    public void setAge(int age)
    {
        this.age.set(age);
    }

    public IntegerProperty ageProperty()
    {
        return this.age;
    }
}

Контроллер ListView: (Модель Initialize, установите ListView и наблюдайте текущее клиентское свойство)

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;

/**
 *
 * @author sedri
 */
public class ListViewController implements Initializable {
   @FXML private ListView<Customer> listView;

   private DataModel model;



    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

    public void initModel(DataModel model)
    {
        // ensure model is only set once:
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }

        listView.getSelectionModel().selectedItemProperty().addListener((obs, oldCustomer, newCustomer) -> 
            model.setCurrentCustomer(newCustomer));

        model.currentCustomerProperty().addListener((obs, oldCustomer, newCustomer) -> {
            if (newCustomer == null) {
                listView.getSelectionModel().clearSelection();
            } else {
                listView.getSelectionModel().select(newCustomer);
            }
        });

        listView.setCellFactory(lv -> new ListCell<Customer>() {
            @Override
            public void updateItem(Customer customer, boolean empty) {
                super.updateItem(customer, empty);
                if (empty) {
                    setText(null);
                } else {
                    setText("Name: " + customer.getName() +  "  Age: " + customer.getAge());
                }
            }
        });

        listView.setItems(model.loadCustomers());
    }
}

ListView FXML:

<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication36.ListViewController">
   <children>
      <ListView fx:id="listView" prefHeight="200.0" prefWidth="200.0" />
   </children>
</StackPane>

DetailsController: (Модель Initialize и наблюдают текущее клиентское свойство)

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;

/**
 * FXML Controller class
 *
 * @author sedri
 */
public class DetailsController implements Initializable {
    @FXML TextField tfName, tfAge;

    private DataModel model;
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

     public void initModel(DataModel model) {
        // ensure model is only set once:
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }

        this.model = model ;

        model.currentCustomerProperty().addListener((observable, oldCustomer, newCustomer) -> {
            if(newCustomer == null){
                tfName.setText("");
                tfAge.setText("");
            }
            else{
                tfName.setText(newCustomer.getName());
                tfAge.setText(Integer.toString(newCustomer.getAge()));
            }
        });
    }
}

Детали FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>


<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication36.DetailsController">
   <children>
      <Label text="Name" />
      <TextField fx:id="tfName" />
      <Label text="Age" />
      <TextField fx:id="tfAge" />
   </children>
   <padding>
      <Insets left="20.0" right="20.0" />
   </padding>
</VBox>

[еще 1139] информация:

@James D отвечают на Образцовом Контроллере представления (MVC) .
код GitHub .

0
ответ дан Sedrick 14 April 2019 в 18:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: