简体   繁体   English

JavaFX FXML控制器ClassNotFoundException

[英]JavaFX FXML controller ClassNotFoundException

I am trying to get a TableView in JavaFX to dynamically display content. 我试图在JavaFX中获得TableView来动态显示内容。

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. 我的控制器名为“ UserInterfaceController.java”,它与FXML文件位于同一软件包下,我也已将该软件包导入了FXML中。 Why can't the controller be found? 为什么找不到控制器?

FXML file: FXML文件:

<?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: 使用FXML的全限定名来引用您的控制器:

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. 解决FXML控制器类时,不搜索FXML文件中的导入。 The controller class type is found via the class loader (I determined this by reading the JavaFX FXMLLoader source code ). 可以通过类加载器找到控制器的类类型(我通过阅读JavaFX FXMLLoader源代码确定了这一点)。 The class loader requires a fully qualified name (specifically, a binary name as per the Java language specification). 类加载器需要一个完全限定的名称(根据Java语言规范,具体来说是一个二进制名称 )。

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 (eg 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. 一旦找到类型,如果没有为fxml加载指定控制器工厂,则FXMLLoader将使用反射实例化控制器本身,否则它将将该作业委派给适当的控制器工厂(例如,与控制器实例关联的控制器工厂)基于Spring依赖注入),但即使在这种情况下,也必须首先由FXMLLoader找到并确定适当的类型,然后才能为控制器要求完全限定的类名。

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. import语句用于解析与文档中FXML元素相对应的Java类型 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. 当您要在FXML中定义新的GridPane时,可以仅引用GridPane而不是javafx.scene.layout.GridPane。

<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. 是的,可能,可以将FXMLLoader编码为也以相同的方式解析控制器类,但是在编写此答案时还没有以这种方式编写。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM