应用程序 start() 方法中的 Javafx 绑定抛出异常
Javafx Binding throw exception in application start() method
UnsupportedOperationException
在将对象绑定到 TableView
时在 Bindings.bindContent()
中抛出。为什么?如何解决这个问题?
我正在使用 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$launchApplication4(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$launchApplication11(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait4(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater3(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$null7(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;
}
}
}
问题出在您对 Arrays.asList(Object...)
的使用上。该方法:
Returns a fixed-size list backed by the specified array.
因此,返回的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:参见 。
基本上,请确保使用支持 add
和 remove
操作的 List
。
您可能想知道为什么首先调用 Bindings.bindContent(List,ObservableList)
会导致 remove
调用。这是因为那个方法 returns:
A content binding [ensuring] that the List
contains the same elements as the ObservableList
. If the content of the ObservableList
changes, the List
will be updated automatically.
换句话说,更新 List
以匹配 ObservableList
。这涉及到在首次创建绑定时清除 List
,然后将 ObservableList
的所有元素添加到其中。
UnsupportedOperationException
在将对象绑定到 TableView
时在 Bindings.bindContent()
中抛出。为什么?如何解决这个问题?
我正在使用 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$launchApplication4(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$launchApplication11(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait4(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater3(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$null7(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;
}
}
}
问题出在您对 Arrays.asList(Object...)
的使用上。该方法:
Returns a fixed-size list backed by the specified array.
因此,返回的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:参见
基本上,请确保使用支持 add
和 remove
操作的 List
。
您可能想知道为什么首先调用 Bindings.bindContent(List,ObservableList)
会导致 remove
调用。这是因为那个方法 returns:
A content binding [ensuring] that the
List
contains the same elements as theObservableList
. If the content of theObservableList
changes, theList
will be updated automatically.
换句话说,更新 List
以匹配 ObservableList
。这涉及到在首次创建绑定时清除 List
,然后将 ObservableList
的所有元素添加到其中。