Javafx Binding throw исключение в методе start () приложения - PullRequest
0 голосов
/ 13 марта 2019

UnsupportedOperationException добавляется Bindings.bindContent() при привязке объектов к TableView.Зачем?Как решить эту проблему?

Я использую Java 8 update181.

 Exception in Application start method java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
 Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
 Caused by: java.lang.UnsupportedOperationException
    at java.util.AbstractList.remove(AbstractList.java:161)
    at java.util.AbstractList$Itr.remove(AbstractList.java:374)
    at java.util.AbstractList.removeRange(AbstractList.java:571)
    at java.util.AbstractList.clear(AbstractList.java:234)
    at com.sun.javafx.binding.ContentBinding.bind(ContentBinding.java:55)
    at javafx.beans.binding.Bindings.bindContent(Bindings.java:1020)
    at problem_bind.Main.start(Main.java:42)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    ... 1 more Exception running application problem_bind.Main

Мои коды:

package problem_bind;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;


public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage)  {
        House house = new House();

        TableView<Person> table = new TableView<>();
        table.setEditable(true);

        TableColumn<Person, String> firstNameColumn = createColumn("First Name", "firstName");
        TableColumn<Person, String> lastNameColumn = createColumn("Last Name", "lastName");
        table.getColumns().add(firstNameColumn);
        table.getColumns().add(lastNameColumn);

        ObservableList<Person> data = FXCollections.observableArrayList();
        data.addAll(house.getPersons());
        table.setItems(data);
        Bindings.bindContent(house.getPersons(), table.getItems());

        BorderPane root = new BorderPane(table, null, null, null, null);
        root.setPadding(new Insets(10));
        primaryStage.setScene(new Scene(root, 600, 600));
        primaryStage.show();
    }


    private TableColumn<Person, String> createColumn(String title, String property) {
        TableColumn<Person, String> col = new TableColumn<>(title);
        col.setSortable(false);
        col.setCellValueFactory(
                new PropertyValueFactory<Person, String>(property));
        col.setCellFactory(TextFieldTableCell.forTableColumn());
        return col ;
    }

    public static class House {
        private List<Person> persons = new ArrayList<Person>();

        public House() {
            this.persons = Arrays.asList(
                    new Person("Jacob", "Smith", this),
                    new Person("Isabella", "Johnson", this),
                    new Person("Ethan", "Williams", this),
                    new Person("Emma", "Jones", this),
                    new Person("Michael", "Brown", this));
        }

        public List<Person> getPersons() {
            return persons;
        }
    }

    public static class Person {
       private String firstName ;
       private String lastName ;
       private House house;

       public Person(String firstName, String lastName, House house) {
           this.firstName = firstName ;
           this.lastName = lastName ;
           this.house = house;
       }

       public String getFirstName() {
           return firstName;
       }

       public void setFirstName(String firstName) {
           this.firstName = firstName;
       }

       public String getLastName() {
           return lastName;
       }

       public void setLastName(String lastName) {
           this.lastName = lastName;
        }

     }
}

1 Ответ

5 голосов
/ 13 марта 2019

Проблема в том, что вы используете Arrays.asList(Object...). Этот метод:

Возвращает список фиксированного размера, подкрепленный указанным массивом.

Из-за этого возвращаемый List не поддерживает такие операции, как add или remove. Вместо этого вы бы изменили такой список с помощью метода set. Первые два метода по своей природе требуют списка переменного размера. Реализация Bindings.bindContent явно пытается использовать эти неподдерживаемые методы при синхронизации списков.

Изменить это:

this.persons = Arrays.asList(
        new Person("Jacob", "Smith", this),
        new Person("Isabella", "Johnson", this),
        new Person("Ethan", "Williams", this),
        new Person("Emma", "Jones", this),
        new Person("Michael", "Brown", this));

К этому:

persons = new ArrayList<>();
persons.add(new Person("Jacob", "Smith", this));
persons.add(new Person("Isabella", "Johnson", this));
persons.add(new Person("Ethan", "Williams", this));
persons.add(new Person("Emma", "Jones", this));
persons.add(new Person("Michael", "Brown", this));

Примечание. В вашем текущем коде префикс this не требуется. Но вы все равно можете использовать его, если хотите.

Примечание № 2: См. @ комментарий Пагбо .

В основном, убедитесь, что вы используете List, который поддерживает операции add и remove.


Возможно, вам интересно, почему вызов Bindings.bindContent(List,ObservableList) приводит к вызову remove. Это потому, что этот метод возвращает:

Привязка содержимого [гарантирует], что List содержит те же элементы, что и ObservableList. Если содержимое ObservableList изменится, List будет обновлено автоматически.

Другими словами, List обновляется в соответствии с ObservableList. При этом сначала создается привязка, очищается List, а затем добавляются все элементы ObservableList.

...