I've checked at least 20 other threads on the subject and tried to debug this the best I can, but I have no clue why it won't work. I want my "addButton" to add my data into my TableView from the TextBoxes when the button is pressed.
My data 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);
}
}
Snippit of the important part of my Controller 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 file:
<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>
The error: (It does this error for every one of the 3 CellProperty lines, this is just 1 but they are all pretty much identical).
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$1.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$2(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$11(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$3(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
The exception arises because PropertyValueFactory
uses reflection to access method calls in your model class Credits
. Because your module is not opened for such access to the javafx.base
module, you get the IllegalAccessException
you posted.
You can fix this by adding a line like the following to your module-info.java
file:
opens org.application to javafx.base ;
Perhaps a better approach is to avoid using PropertyValueFactory
. That class was really designed because, prior to Java 8 and lambda expressions, creating a CellValueFactory
simply to access a property in a model class was pretty cumbersome. With the advent of lambda expression in Java 8, this is no longer the case, and using a lambda expression instead of the reflective PropertyValueFactory
probably gives better performance, and, more importantly, provides compile-time checking.
First (and you should do this regardless), add property accessor methods to your Credits
class. As your class currently stands, you create StringProperty
instances, but there are no methods to access them (only methods to access their content). Consequently, your table won't dynamically update if you call, e.g. setTitle()
on an already-displayed Credits
instance. You just need to add
public class Credits {
// all existing code...
public StringProperty titleProperty() {
return title ;
}
public StringProperty occupationProperty() {
return occupation ;
}
public StringProperty personProperty() {
return person ;
}
}
Now you can just reference the properties directly in your Credits
class:
title.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
and similarly for the other columns. As well as the other benefits (primarily compile-time checking that the property actually exists), this also avoids the need to expose your Credits
class reflectively to the javafx.base
module.