I am trying to get a TableView in JavaFX to dynamically display content.
When I run my program I get this error:
java.lang.ClassNotFoundException: UserInterfaceController
My controller is named "UserInterfaceController.java", it's under the same package as the FXML file and I have imported the package in the FXML as well. Why can't the controller be found?
FXML file:
<?import javafx.collections.*?>
<?import javafx.geometry.Insets?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<?import d1example2.*?>
<GridPane alignment="center" hgap="10.0" vgap="10.0" fx:controller="UserInterfaceController"
xmlns:fx="http://javafx.com/fxml">
<TableView fx:id="tableView" GridPane.columnIndex="0" GridPane.rowIndex="1">
<columns>
</columns>
</TableView>
</GridPane>
Controller:
package d1example2;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Text;
import javafx.util.Callback;
public class UserInterfaceController implements Initializable {
private Label label;
@FXML
private AnchorPane MainPane;
@FXML
private TextField FirstField;
@FXML
private Text TimesText;
@FXML
private Text EqualSign;
@FXML
private Text EquationResult;
@FXML
private TableColumn<?, ?> HalfColumn;
@FXML
private TableColumn<?, ?> DoubleColumn;
@FXML
private Button SubmitButton;
@FXML private TableView tableView;
@FXML
public void initialize(URL url, ResourceBundle rb) {
List<String> columns = new ArrayList<String>();
columns.add("col1");
columns.add("col2");
TableColumn [] tableColumns = new TableColumn[columns.size()];
int columnIndex = 0;
for(int i=0 ; i<columns.size(); i++) {
final int j = i;
TableColumn col = new TableColumn(columns.get(i));
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableView.getColumns().addAll(col);
}
ObservableList<String> row = FXCollections.observableArrayList();
ObservableList<String> row1 = FXCollections.observableArrayList();
row.addAll("d1");
row.addAll("d11");
row1.addAll("d2");
row1.addAll("d22");
tableView.getItems().add(row);
tableView.getItems().add(row1);
}
@FXML
private void handleButtonAction(MouseEvent event) {
}
}
Main Class:
package d1example2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class D1Example2 extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("FXML TableView Example");
Pane myPane = (Pane)FXMLLoader.load(getClass().getResource("UserInterface.fxml"));
Scene myScene = new Scene(myPane);
primaryStage.setScene(myScene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Reference your controller from FXML using it's fully qualified name:
fx:controller="d1example2.UserInterfaceController"
Answers to follow-up questions
Answers to the following questions explain why this is so, but you don't necessarily need to understand why if you don't want to, the following is purely informational.
Why must it be fully qualified when he has an import statement?
The imports in the FXML file are not searched when resolving the FXML controller class. The controller class type is found via the class loader (I determined this by reading the JavaFX FXMLLoader source code). The class loader requires a fully qualified name (specifically, a binary name as per the Java language specification).
Once the type is found, if no controller factory has been specified for the fxml loading, then the FXMLLoader will instantiate the controller itself using reflection, otherwise it will delegate that job to an appropriate controller factory (e.g. a controller factory that associates a controller instance based upon Spring dependency injection) but even in that instance, the appropriate type must be found and determined by the FXMLLoader first and to do that it requires a fully qualified classname for the controller.
What's the point of import statements if I need to do that anyway?
The import statements are used for resolving the Java types corresponding to the FXML elements in the document. That way, the document can contain the line:
<?import javafx.scene.layout.*?>
And you can just reference GridPane instead of javafx.scene.layout.GridPane, when you want to define a new GridPane in your FXML.
<GridPane alignment="center" ...>
Yes, potentially, the FXMLLoader could have been coded to also resolve controller classes in the same manner, but it just hasn't been written that way at the time that this answer was written.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With