为什么我无法在另一个FXML中将项添加到表中?

时间:2016-09-25 15:06:19

标签: java javafx controller fxml

我尝试制作两个fxml文件。第一个是主要的fxml。第二个是TableView的fxml。我把它们放在一起。

这是Main类:

package sceneBuilder;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Ana extends Application{

    private Stage window;
    private BorderPane layout;

    @Override
    public void start(Stage args) throws Exception {
        try{
            window = args;
            showMainView();
            showMainItems();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }


    private void showMainView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Ana.class.getResource("interface.fxml"));
        layout = loader.load();
        Scene scene = new Scene(layout);
        window.setScene(scene);
        window.show();

    }

    private void showMainItems() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Ana.class.getResource("interface2.fxml"));
        BorderPane layout2 = loader.load();
        layout.setCenter(layout2);

    }

    public static void main(String[] args) {
        launch(args);
    }
}

这是主FXML的控制器(Controller.java):

package sceneBuilder;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;

public class Controller implements Initializable{

    //TreeView
    @FXML
    private TreeView<String> mainTree = new TreeView<>();

    //TextFields
    @FXML
    private TextField txtf1 = new TextField();
    @FXML
    private TextField txtf2 = new TextField();
    @FXML
    private TextField txtf3 = new TextField();

    @Override
    public void initialize(URL location, ResourceBundle recources) {
        TreeItem<String> root = new TreeItem<>("Tables");
        TreeItem<String> table1 = new TreeItem<>("Table-1");
        TreeItem<String> table2 = new TreeItem<>("Table-2");
        root.getChildren().add(table1);
        root.getChildren().add(table2);
        mainTree.setRoot(root);
        mainTree.setShowRoot(false);
    }

    @FXML
     void addClicked(ActionEvent event) throws Exception{
        FXMLLoader loader = new FXMLLoader(getClass().getResource("interface2.fxml"));
        Controller2 controller = loader.getController();
        controller.addData(txtf1.getText(), txtf2.getText(), txtf3.getText());
        }

    @FXML
     void deleteClicked(ActionEvent event){
        FXMLLoader loader = new FXMLLoader(getClass().getResource("interface2.fxml"));
        Controller2 controller = loader.getController();
        controller.addData(txtf1.getText(), txtf2.getText(), txtf3.getText());
        }


}

这是TableView的Controller(Controller2.java):

package sceneBuilder;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class Controller2 implements Initializable{

    //Table and columns
    @FXML
    private TableView<Product> table = new TableView<>();
    @FXML
    private TableColumn<Product, String> nameColumn = new TableColumn<>();
    @FXML
    private TableColumn<Product, String> priceColumn = new TableColumn<>();
    @FXML
    private TableColumn<Product, String> quantityColumn = new TableColumn<>();


    //Items
    ObservableList<Product> data = FXCollections.observableArrayList(
            new Product("Tablet", "20", "1200,00"),
            new Product("Samsung Note 7", "50", "3450,00"),
            new Product("Kitap", "1000", "50,00")   
    );

    //Column settings
    @Override
    public void initialize(URL location, ResourceBundle recources) {
        nameColumn.setCellValueFactory(new PropertyValueFactory<Product, String>("ad"));
        priceColumn.setCellValueFactory(new PropertyValueFactory<Product, String>("fiyat"));        
        quantityColumn.setCellValueFactory(new PropertyValueFactory<Product, String>("miktar"));

        table.setItems(data);
    }

    public void addData(String t1, String t2, String t3){
        //Add data
        Product satir = new Product(t1, t2, t3);

        data.add(satir);
    }

    public void deleteData(){
        ObservableList<Product> productSelected, allProducts;
        allProducts = table.getItems();
        productSelected = table.getSelectionModel().getSelectedItems();

        productSelected.forEach(allProducts::remove);
    }
}

这就是问题:我想在TableView中添加或删除项目。所以我创建了三个TextField和两个按钮。我为按钮设置了setOnAction方法。在Controller.java中,我获取了TableView的FXML(interface2.fxml)文件。并尝试启动TableView的Controller(Controller2.java)中存在的addItem方法。但只要我填充TextFields并单击添加或删除按钮,它就会给我java.lang.reflect.InvocationTargetExceptionjava.lang.NullPointerException。 我不知道为什么???请帮我。我不太懂英语,所以请不要写严厉的句子。 (除了编程术语)。

如果需要,这些是fxml文件: Main fxml :( interface.fxml)

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sceneBuilder.Controller">
   <top>
      <VBox BorderPane.alignment="CENTER">
         <children>
            <MenuBar>
              <menus>
                <Menu mnemonicParsing="false" text="Dosya">
                  <items>
                    <MenuItem mnemonicParsing="false" text="Yeni" />
                        <MenuItem mnemonicParsing="false" text="Kaydet" />
                  </items>
                </Menu>
                <Menu mnemonicParsing="false" text="Yardım">
                  <items>
                    <MenuItem mnemonicParsing="false" text="Hakkında" />
                  </items>
                </Menu>
              </menus>
            </MenuBar>
            <HBox spacing="8.0">
               <children>
                  <TextField fx:id="txtf1" promptText="İsim" />
                  <TextField fx:id="txtf2" layoutX="10.0" layoutY="10.0" promptText="Fiyat" />
                  <TextField fx:id="txtf3" layoutX="175.0" layoutY="18.0" promptText="Miktar" />
                  <Region HBox.hgrow="ALWAYS" />
                  <Button maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#addClicked" text="Ekle" textAlignment="CENTER" textOverrun="CLIP">
                     <padding>
                        <Insets bottom="4.0" left="10.0" right="10.0" top="4.0" />
                     </padding></Button>
                  <Button layoutX="159.0" layoutY="10.0" mnemonicParsing="false" onAction="#deleteClicked" text="Sil">
                     <padding>
                        <Insets bottom="4.0" left="15.0" right="15.0" top="4.0" />
                     </padding></Button>
               </children>
               <padding>
                  <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
               </padding>
            </HBox>
         </children>
      </VBox>
   </top>
   <left>
      <TreeView fx:id="mainTree" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
   </left>
   <bottom>
      <Label text="Sorunlar:" BorderPane.alignment="CENTER_LEFT">
         <padding>
            <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
         </padding></Label>
   </bottom>
   <center>
      <TableView fx:id="table" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
        <columns>
          <TableColumn fx:id="nameColumn" prefWidth="75.0" text="C1" />
          <TableColumn fx:id="priceColumn" prefWidth="75.0" text="C2" />
            <TableColumn fx:id="quantityColumn" prefWidth="75.0" text="Column X" />
        </columns>
      </TableView>
   </center>
</BorderPane>

TableView的FXML(interface2.fxml):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sceneBuilder.Controller2">
   <center>
      <TableView fx:id="table" BorderPane.alignment="CENTER">
        <columns>
          <TableColumn fx:id="nameColumn" maxWidth="200.0" minWidth="200.0" prefWidth="200.0" resizable="false" text="Ad" />
          <TableColumn fx:id="priceColumn" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" text="Fiyat" />
            <TableColumn fx:id="quantityColumn" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" text="Miktar" />
        </columns>
      </TableView>
   </center>
</BorderPane>

1 个答案:

答案 0 :(得分:2)

您需要在两个控制器之间共享数据。你可以这样做:

public class Controller2 implements Initializable {

    // existing code...

    public ObservableList<Product> getData() {
        return data ;
    }
}

然后给第一个控制器一个数据引用:

public class Controller implements Initializable {

    private ObservableList<Product> data ;

    public ObservableList<Product> getData() {
        return data ;
    }

    public void setData(ObservableList<Product> data) {
        this.data = data ;
    }

    // ...

    @FXML
    void addClicked(ActionEvent event) {
        data.add(new Product(txtf1.getText(), txtf2.getText(), txtf3.getText());
    }

    // etc ...
}

然后你可以将它们与

结合在一起
public class Ana extends Application{

    private Stage window;
    private BorderPane layout;

    @Override
    public void start(Stage args) throws Exception {
        try{
            window = args;
            Controller mainController = showMainView();
            Controller2 controller = showMainItems();
            mainController.setData(controller.getData());
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }


    private Controller showMainView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Ana.class.getResource("interface.fxml"));
        layout = loader.load();
        Scene scene = new Scene(layout);
        window.setScene(scene);
        window.show();
        return loader.getController();
    }

    private Controller2 showMainItems() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Ana.class.getResource("interface2.fxml"));
        BorderPane layout2 = loader.load();
        layout.setCenter(layout2);
        return loader.getController();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

另请参阅Applying MVC With JavaFx了解此想法的其他版本。 (在该问题的答案中,数据被移动到它自己的类中,这可能更好。)