JavaFX setCellValueFactory 无法检索 属性 IllegalAcessException
JavaFX setCellValueFactory cannot retrieve property IllegalAcessException
我已经检查了至少 20 个关于该主题的其他线程并尝试尽我所能对其进行调试,但我不知道为什么它不起作用。我希望我的 "addButton" 在按下按钮时将我的数据从文本框添加到我的 TableView 中。
我的数据class:
package org.application;
import javafx.beans.property.SimpleStringProperty;
public class Credits {
private SimpleStringProperty title;
private SimpleStringProperty occupation;
private SimpleStringProperty person;
public Credits (String title, String occupation, String person){
this.title = new SimpleStringProperty(title);
this.occupation = new SimpleStringProperty(occupation);
this.person = new SimpleStringProperty(person);
}
public String getTitle() {
return this.title.get();
}
public void setTitle(String title) {
this.title.set(title);
}
public String getOccupation() {
return this.occupation.get();
}
public void setOccupation(String occupation) {
this.occupation.set(occupation);
}
public String getPerson() {
return this.person.get();
}
public void setPerson(String name) {
this.person.set(name);
}
}
我的控制器重要部分的片段class
public Button searchButton;
public Button addButton;
public Button deleteButton;
public Button updateButton;
public TextField searchBox;
public TextField setTitleBox;
public TextField setOccupationBox;
public TextField setPersonBox;
public TableView creditTable;
public TableColumn title;
public TableColumn occupation;
public TableColumn person;
public ListView test;
final ObservableList<Credits> credits = FXCollections.observableArrayList();
public void initialize() {
title.setCellValueFactory(new PropertyValueFactory<Credits, String>("title"));
occupation.setCellValueFactory(new PropertyValueFactory<Credits, String>("occupation"));
person.setCellValueFactory(new PropertyValueFactory<Credits, String>("person"));
}
public void addButton(ActionEvent event) {
String title = setTitleBox.getText();
String occupation = setOccupationBox.getText();
String person = setPersonBox.getText();
credits.add(new Credits(title, occupation, person));
creditTable.setItems(credits);
}
fxml 文件:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" styleClass="rightSide" stylesheets="@../../ECMS.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.presentation.MainMenu">
<children>
<Button fx:id="loginButton" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#switchToLoginScreen" styleClass="loginButton" text="Login" />
<TextField fx:id="searchBox" layoutX="14.0" layoutY="108.0" prefHeight="30.0" prefWidth="195.0" promptText="Name" />
<Button fx:id="searchButton" layoutX="214.0" layoutY="108.0" mnemonicParsing="false" prefHeight="30.0" prefWidth="100.0" styleClass="loginButton" text="Search" />
<Button fx:id="helpButton" layoutX="63.0" layoutY="14.0" mnemonicParsing="false" onAction="#switchToHelpPopup" styleClass="loginButton" text="Help" />
<Label layoutX="14.0" layoutY="86.0" prefHeight="17.0" prefWidth="162.0" text="Search for productions:">
<font>
<Font name="Ebrima Bold" size="14.0" />
</font></Label>
<ListView fx:id="test" layoutX="14.0" layoutY="143.0" prefHeight="450.0" prefWidth="300.0" />
<Button fx:id="closeButton" layoutX="775.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#closeButtonAction" prefHeight="20.0" prefWidth="25.0" styleClass="closeButton" text="X">
<font>
<Font name="Eras Bold ITC" size="12.0" />
</font></Button>
<Button fx:id="addButton" layoutX="363.0" layoutY="93.0" mnemonicParsing="false" onAction="#addButton" prefHeight="31.0" prefWidth="100.0" text="Add" />
<Button fx:id="deleteButton" layoutX="504.0" layoutY="93.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="100.0" text="Delete" />
<Button fx:id="updateButton" layoutX="652.0" layoutY="93.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="100.0" text="Update" />
<TableView fx:id="creditTable" editable="true" layoutX="332.0" layoutY="143.0" prefHeight="450.0" prefWidth="450.0">
<columns>
<TableColumn fx:id="title" prefWidth="147.0" text="Title" />
<TableColumn fx:id="occupation" minWidth="0.0" prefWidth="132.0" text="Occupation" />
<TableColumn fx:id="person" minWidth="-1.0" prefWidth="170.0" text="Person" />
</columns>
</TableView>
<TextField fx:id="setPersonBox" layoutX="634.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Person" />
<Label layoutX="500.0" layoutY="30.0" prefHeight="18.0" prefWidth="114.0" text="Add production:">
<font>
<Font name="Ebrima Bold" size="14.0" />
</font>
</Label>
<TextField fx:id="setOccupationBox" layoutX="489.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Occupation" />
<TextField fx:id="setTitleBox" layoutX="345.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Title" />
</children>
</AnchorPane>
错误:(它对 3 个 CellProperty 行中的每一行都会出现此错误,这只是 1 行,但它们几乎完全相同)。
Apr 19, 2020 7:20:12 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'title' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@210cabaf with provided class type: class org.application.Credits
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class org.application.Credits (in module org.example) because module org.example does not open org.application to javafx.base
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:176)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.getCellDataReflectively(PropertyValueFactory.java:184)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:154)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:133)
at javafx.controls/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:593)
at javafx.controls/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578)
at javafx.controls/javafx.scene.control.TableCell.updateItem(TableCell.java:646)
at javafx.controls/javafx.scene.control.TableCell.indexChanged(TableCell.java:469)
at javafx.controls/javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:120)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:539)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.<init>(TableRowSkinBase.java:159)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:89)
at javafx.controls/javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:213)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:897)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:145)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9540)
at javafx.graphics/javafx.scene.Node.applyCss(Node.java:9627)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1749)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1726)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1852)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2755)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1245)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1206)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1213)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1213)
at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2482)
at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse(Toolkit.java:412)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:411)
at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:438)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:563)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:543)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:536)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit(QuantumToolkit.java:342)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.IllegalAccessException: module javafx.base cannot access class org.application.Credits (in module org.example) because module org.example does not open org.application to javafx.base
at javafx.base/com.sun.javafx.property.MethodHelper.invoke(MethodHelper.java:69)
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:174)
... 40 more
出现异常是因为 PropertyValueFactory
使用反射来访问模型中的方法调用 class Credits
。因为您的模块没有打开以访问 javafx.base
模块,所以您得到了您发布的 IllegalAccessException
。
您可以通过在 module-info.java
文件中添加如下一行来解决此问题:
opens org.application to javafx.base ;
也许更好的方法是避免使用 PropertyValueFactory
。 class 的真正设计是因为,在 Java 8 和 lambda 表达式之前,创建一个 CellValueFactory
只是为了访问模型 class 中的 属性 非常麻烦.随着 Java 8 中 lambda 表达式的出现,情况不再如此,使用 lambda 表达式代替反射 PropertyValueFactory
可能会提供更好的性能,更重要的是,提供编译时检查.
首先(无论如何您都应该这样做),将 属性 访问器方法添加到您的 Credits
class。正如您的 class 目前所处的状态,您创建了 StringProperty
个实例,但没有访问它们的方法(只有访问其内容的方法)。因此,如果您调用,您的 table 将不会动态更新,例如setTitle()
在已显示的 Credits
实例上。你只需要添加
public class Credits {
// all existing code...
public StringProperty titleProperty() {
return title ;
}
public StringProperty occupationProperty() {
return occupation ;
}
public StringProperty personProperty() {
return person ;
}
}
现在您可以直接在 Credits
class:
中引用属性
title.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
其他列也是如此。除了其他好处(主要是编译时检查 属性 是否确实存在),这也避免了将 Credits
class 反射地暴露给 javafx.base
模块的需要.
我已经检查了至少 20 个关于该主题的其他线程并尝试尽我所能对其进行调试,但我不知道为什么它不起作用。我希望我的 "addButton" 在按下按钮时将我的数据从文本框添加到我的 TableView 中。
我的数据class:
package org.application;
import javafx.beans.property.SimpleStringProperty;
public class Credits {
private SimpleStringProperty title;
private SimpleStringProperty occupation;
private SimpleStringProperty person;
public Credits (String title, String occupation, String person){
this.title = new SimpleStringProperty(title);
this.occupation = new SimpleStringProperty(occupation);
this.person = new SimpleStringProperty(person);
}
public String getTitle() {
return this.title.get();
}
public void setTitle(String title) {
this.title.set(title);
}
public String getOccupation() {
return this.occupation.get();
}
public void setOccupation(String occupation) {
this.occupation.set(occupation);
}
public String getPerson() {
return this.person.get();
}
public void setPerson(String name) {
this.person.set(name);
}
}
我的控制器重要部分的片段class
public Button searchButton;
public Button addButton;
public Button deleteButton;
public Button updateButton;
public TextField searchBox;
public TextField setTitleBox;
public TextField setOccupationBox;
public TextField setPersonBox;
public TableView creditTable;
public TableColumn title;
public TableColumn occupation;
public TableColumn person;
public ListView test;
final ObservableList<Credits> credits = FXCollections.observableArrayList();
public void initialize() {
title.setCellValueFactory(new PropertyValueFactory<Credits, String>("title"));
occupation.setCellValueFactory(new PropertyValueFactory<Credits, String>("occupation"));
person.setCellValueFactory(new PropertyValueFactory<Credits, String>("person"));
}
public void addButton(ActionEvent event) {
String title = setTitleBox.getText();
String occupation = setOccupationBox.getText();
String person = setPersonBox.getText();
credits.add(new Credits(title, occupation, person));
creditTable.setItems(credits);
}
fxml 文件:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" styleClass="rightSide" stylesheets="@../../ECMS.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.presentation.MainMenu">
<children>
<Button fx:id="loginButton" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#switchToLoginScreen" styleClass="loginButton" text="Login" />
<TextField fx:id="searchBox" layoutX="14.0" layoutY="108.0" prefHeight="30.0" prefWidth="195.0" promptText="Name" />
<Button fx:id="searchButton" layoutX="214.0" layoutY="108.0" mnemonicParsing="false" prefHeight="30.0" prefWidth="100.0" styleClass="loginButton" text="Search" />
<Button fx:id="helpButton" layoutX="63.0" layoutY="14.0" mnemonicParsing="false" onAction="#switchToHelpPopup" styleClass="loginButton" text="Help" />
<Label layoutX="14.0" layoutY="86.0" prefHeight="17.0" prefWidth="162.0" text="Search for productions:">
<font>
<Font name="Ebrima Bold" size="14.0" />
</font></Label>
<ListView fx:id="test" layoutX="14.0" layoutY="143.0" prefHeight="450.0" prefWidth="300.0" />
<Button fx:id="closeButton" layoutX="775.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#closeButtonAction" prefHeight="20.0" prefWidth="25.0" styleClass="closeButton" text="X">
<font>
<Font name="Eras Bold ITC" size="12.0" />
</font></Button>
<Button fx:id="addButton" layoutX="363.0" layoutY="93.0" mnemonicParsing="false" onAction="#addButton" prefHeight="31.0" prefWidth="100.0" text="Add" />
<Button fx:id="deleteButton" layoutX="504.0" layoutY="93.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="100.0" text="Delete" />
<Button fx:id="updateButton" layoutX="652.0" layoutY="93.0" mnemonicParsing="false" prefHeight="31.0" prefWidth="100.0" text="Update" />
<TableView fx:id="creditTable" editable="true" layoutX="332.0" layoutY="143.0" prefHeight="450.0" prefWidth="450.0">
<columns>
<TableColumn fx:id="title" prefWidth="147.0" text="Title" />
<TableColumn fx:id="occupation" minWidth="0.0" prefWidth="132.0" text="Occupation" />
<TableColumn fx:id="person" minWidth="-1.0" prefWidth="170.0" text="Person" />
</columns>
</TableView>
<TextField fx:id="setPersonBox" layoutX="634.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Person" />
<Label layoutX="500.0" layoutY="30.0" prefHeight="18.0" prefWidth="114.0" text="Add production:">
<font>
<Font name="Ebrima Bold" size="14.0" />
</font>
</Label>
<TextField fx:id="setOccupationBox" layoutX="489.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Occupation" />
<TextField fx:id="setTitleBox" layoutX="345.0" layoutY="54.0" prefHeight="30.0" prefWidth="136.0" promptText="Title" />
</children>
</AnchorPane>
错误:(它对 3 个 CellProperty 行中的每一行都会出现此错误,这只是 1 行,但它们几乎完全相同)。
Apr 19, 2020 7:20:12 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'title' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@210cabaf with provided class type: class org.application.Credits
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class org.application.Credits (in module org.example) because module org.example does not open org.application to javafx.base
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:176)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.getCellDataReflectively(PropertyValueFactory.java:184)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:154)
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:133)
at javafx.controls/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:593)
at javafx.controls/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578)
at javafx.controls/javafx.scene.control.TableCell.updateItem(TableCell.java:646)
at javafx.controls/javafx.scene.control.TableCell.indexChanged(TableCell.java:469)
at javafx.controls/javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:120)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:539)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.<init>(TableRowSkinBase.java:159)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:89)
at javafx.controls/javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:213)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:897)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:145)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9540)
at javafx.graphics/javafx.scene.Node.applyCss(Node.java:9627)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1749)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1726)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1852)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2755)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1245)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1206)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1213)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1213)
at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2482)
at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse(Toolkit.java:412)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:411)
at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:438)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:563)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:543)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:536)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit(QuantumToolkit.java:342)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.IllegalAccessException: module javafx.base cannot access class org.application.Credits (in module org.example) because module org.example does not open org.application to javafx.base
at javafx.base/com.sun.javafx.property.MethodHelper.invoke(MethodHelper.java:69)
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:174)
... 40 more
出现异常是因为 PropertyValueFactory
使用反射来访问模型中的方法调用 class Credits
。因为您的模块没有打开以访问 javafx.base
模块,所以您得到了您发布的 IllegalAccessException
。
您可以通过在 module-info.java
文件中添加如下一行来解决此问题:
opens org.application to javafx.base ;
也许更好的方法是避免使用 PropertyValueFactory
。 class 的真正设计是因为,在 Java 8 和 lambda 表达式之前,创建一个 CellValueFactory
只是为了访问模型 class 中的 属性 非常麻烦.随着 Java 8 中 lambda 表达式的出现,情况不再如此,使用 lambda 表达式代替反射 PropertyValueFactory
可能会提供更好的性能,更重要的是,提供编译时检查.
首先(无论如何您都应该这样做),将 属性 访问器方法添加到您的 Credits
class。正如您的 class 目前所处的状态,您创建了 StringProperty
个实例,但没有访问它们的方法(只有访问其内容的方法)。因此,如果您调用,您的 table 将不会动态更新,例如setTitle()
在已显示的 Credits
实例上。你只需要添加
public class Credits {
// all existing code...
public StringProperty titleProperty() {
return title ;
}
public StringProperty occupationProperty() {
return occupation ;
}
public StringProperty personProperty() {
return person ;
}
}
现在您可以直接在 Credits
class:
title.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
其他列也是如此。除了其他好处(主要是编译时检查 属性 是否确实存在),这也避免了将 Credits
class 反射地暴露给 javafx.base
模块的需要.