JavaFX GUI - 为什么删除按钮功能不能与TableView一起使用?

时间:2016-12-01 01:44:56

标签: java user-interface javafx tableview eventhandler

您好,这是我作为Java和GUI设计新手的第一个问题。 我遇到了一个奇怪的情况,我觉得我只是在看。 我有一些TableView信息,也可以使用Add Button添加。在我添加FilterList构造函数之前,Delete Button正在工作,因此我可以按ID过滤搜索结果。添加该功能后,删除按钮停止工作。我个人认为deleteButtonClicked类不再正确检测表,因为通过添加Filter功能进行了更改。但是,尽管我试图保持两者,但其中一个通常会停止工作。我目前正在努力让它在没有Delete Button类的情况下工作,可能只是将产品设为null。

TableView函数位于代码的顶部,而删除按钮和函数位于底部。

package application;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;

public class MainApp extends Application {



    TableView<Product> table = new TableView<>();


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

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane root = new BorderPane();

        BorderPane leftPane = new BorderPane();

        FilteredList<Product> filterList = new FilteredList<>(productData);

        table.setEditable(true);
        //table.setItems(productData); // DELETE BUTTON WORKS WHEN THIS ONE IS ONLY SET
        table.setItems(filterList); // DELETE BUTTON DOESN'T WORK WHEN
                                    // THIS IS SET BUT, IS NEEDED TO FILTER SEARCH FUNCTIONS

        TableColumn<Product, String> idNumberCol = new TableColumn<>("ID Number");
        idNumberCol.setMinWidth(50);
        idNumberCol.setCellValueFactory(new PropertyValueFactory<>("idNumber"));

        idNumberCol.setCellFactory(TextFieldTableCell.<Product>forTableColumn());
        idNumberCol.setOnEditCommit(
        (CellEditEvent<Product, String> t) -> {
        ((Product) t.getTableView().getItems().get(
            t.getTablePosition().getRow())
            ).setIdNumber(t.getNewValue());
});

        TableColumn<Product, String> desCol = new TableColumn<>("Description");
        desCol.setMinWidth(150);
        desCol.setCellValueFactory(new PropertyValueFactory<>("description")); 

        desCol.setCellFactory(TextFieldTableCell.<Product>forTableColumn());
        desCol.setOnEditCommit(
        (CellEditEvent<Product, String> t) -> {
        ((Product) t.getTableView().getItems().get(
            t.getTablePosition().getRow())
            ).setDescription(t.getNewValue());
});

        TableColumn<Product, String> expCol = new TableColumn<>("Expiration");
        expCol.setMinWidth(100);
        expCol.setCellValueFactory(new PropertyValueFactory<>("expiration"));

        expCol.setCellFactory(TextFieldTableCell.<Product>forTableColumn());
        expCol.setOnEditCommit(
        (CellEditEvent<Product, String> t) -> {
        ((Product) t.getTableView().getItems().get(
            t.getTablePosition().getRow())
            ).setExpiration(t.getNewValue());
});


        table.getColumns().addAll(idNumberCol, desCol, expCol);


        VBox leftVbox = new VBox(); 
        leftVbox.setPadding(new Insets(10, 20, 20, 20)); 
        leftVbox.setSpacing(10);
        leftVbox.getChildren().addAll(table);

        BorderPane topPane = new BorderPane();

        HBox topHbox = new HBox(); //Create HBox
        topHbox.setPadding(new Insets(20, 20, 10, 20)); // Set padding and spacing for the hbox
        topHbox.setSpacing(10); // The hbox will appropriately space out more

        Text txtSearch = new Text("Search: ");
        topHbox.getChildren().add(txtSearch);
        txtSearch.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16));

        TextField txt = new TextField(""); // Create new TextField
        txt.setPrefWidth(250);
        txt.setPromptText("Search A Product ID"); // Sets up hint text inside the TextField
        topHbox.getChildren().add(txt); // Add the TextField to the second hbox

        HBox rightHbox = new HBox(); //Create HBox
        rightHbox.setPadding(new Insets(20, 20, 10, 20)); // Set padding and spacing for the hbox
        rightHbox.setSpacing(10); // The hbox will appropriately space out more

        Text txtDetails = new Text("Product Details");
        rightHbox.getChildren().add(txtDetails);
        txtDetails.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));

        txt.textProperty().addListener((obsVal, oldValue, newValue) -> {
        filterList.setPredicate(product -> product.getIdNumber().contains(newValue));
        });


        BorderPane rightPane = new BorderPane();

        VBox rightVbox = new VBox();
        rightVbox.setPadding(new Insets(20, 10, 10, 20));
        rightVbox.setSpacing(30);
        rightVbox.setAlignment(Pos.TOP_LEFT);

        Text txtId = new Text("ID: ");
        rightVbox.getChildren().add(txtId);
        txtId.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16));

        Text txtDes = new Text("Description: ");
        rightVbox.getChildren().add(txtDes);
        txtDes.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

        Text txtExp = new Text("Expiration: ");
        rightVbox.getChildren().add(txtExp);
        txtExp.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

        Text txtStatus = new Text("Status: ");
        rightVbox.getChildren().add(txtStatus);
        txtStatus.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

        Text txtEnter = new Text("Entered By: ");
        rightVbox.getChildren().add(txtEnter);
        txtEnter.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

        //EMPTY PLACE HOLDER INFORMATION TO POPULATE THE DATA
        Label lblId;
        Label lblDes;
        Label lblExp;
        Label lblStatus;
        Label lblEnter;

        HBox bottomHbox2 = new HBox();
        bottomHbox2.setPadding(new Insets(20, 20, 20, 20));
        bottomHbox2.setSpacing(10);
        bottomHbox2.setAlignment(Pos.BOTTOM_RIGHT);


        Button btnNew = new Button("Add...");
        bottomHbox2.getChildren().add(btnNew);
        btnNew.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

            Stage secondStage = new Stage();

            BorderPane dialogPane = new BorderPane();

            VBox dialogVbox = new VBox();
            dialogVbox.setPadding(new Insets(20, 10, 20, 20));
            dialogVbox.setSpacing(20);     

            TextField addId = new TextField();
            addId.setPromptText("ID Number");
            addId.setMinWidth(50);
            //addId.setMaxWidth(idNumberCol.getPrefWidth());

            TextField addDes = new TextField();
            addDes.setPromptText("Description");
            addDes.setMinWidth(100);
            //addDes.setMaxWidth(desCol.getPrefWidth());

            TextField addExp = new TextField();
            addExp.setPromptText("Expiration Date");
            addExp.setMinWidth(50);
            //addExp.setMaxWidth(expCol.getPrefWidth());

            dialogVbox.getChildren().addAll(addId, addDes, addExp);

            VBox dialogVbox2 = new VBox();
            dialogVbox2.setPadding(new Insets(20, 20, 20, 10));
            dialogVbox2.setSpacing(20);     

            Text txtIdLabel = new Text("ID: ");
            dialogVbox2.getChildren().add(txtIdLabel);
            txtIdLabel.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16));

            Text txtDesLabel = new Text("Description: ");
            dialogVbox2.getChildren().add(txtDesLabel);
            txtDesLabel.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

            Text txtExpLabel = new Text("Expiration: ");
            dialogVbox2.getChildren().add(txtExpLabel);
            txtExpLabel.setFont(Font.font("Tahoma", FontWeight.NORMAL, 16)); 

            HBox addHbox = new HBox();
            addHbox.setPadding(new Insets(20, 10, 50, 20));
            addHbox.setSpacing(10);
            addHbox.setAlignment(Pos.BOTTOM_RIGHT);

            Button btnAdd = new Button("Add Product");
            addHbox.getChildren().add(btnAdd);

            btnAdd.setOnAction((ActionEvent e) -> {
            productData.add(new Product(
                    addId.getText(),
                    addDes.getText(),
                    addExp.getText()));
            addId.clear();
            addDes.clear();
            addExp.clear();
        });

                Button btnClose = new Button("Close");
        addHbox.getChildren().add(btnClose);

        btnClose.setOnAction(new EventHandler<ActionEvent>(){

                 @Override
                 public void handle(ActionEvent arg0) {
                     secondStage.close();
                 }

             });

            dialogPane.setCenter(dialogVbox);
            dialogPane.setLeft(dialogVbox2);
            dialogPane.setBottom(addHbox);

            Scene scene2 = new Scene(dialogPane, 400, 200);

            secondStage.setTitle("Add New Product");
            secondStage.setScene(scene2);
            secondStage.show();

                //Set position of second window, related to primary window.
                secondStage.setX(primaryStage.getX() + 250);
                secondStage.setY(primaryStage.getY() + 100);

                secondStage.show();
            }
        });

        // DELETE BUTTON & EVENT HANDLER
        Button btnDelete = new Button("Delete");
        bottomHbox2.getChildren().add(btnDelete);

        btnDelete.setOnAction(new EventHandler<ActionEvent>(){

                 @Override
                 public void handle(ActionEvent arg0) {
                     deleteButtonClicked();
                 }

             });


        Button btnSave = new Button("Save & Exit");
        bottomHbox2.getChildren().add(btnSave);

        btnSave.setOnAction(new EventHandler<ActionEvent>(){

                 @Override
                 public void handle(ActionEvent arg0) {
                     primaryStage.close();
                 }

             });

        rightVbox.getChildren().add(bottomHbox2);

        topPane.setLeft(topHbox);
        topPane.setCenter(rightHbox);
        leftPane.setLeft(leftVbox);
        rightPane.setLeft(rightVbox);
        //rightPane.setCenter(bottomHbox2);

        root.setTop(topPane);
        root.setLeft(leftPane);
        root.setCenter(rightPane);

        Scene scene = new Scene(root, 650, 500);
        primaryStage.setTitle("Perishables Application");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // DELETE BUTTON FUNCTION
    public void deleteButtonClicked() {
        ObservableList<Product> productSelected, productData;
        productData = table.getItems();
        productSelected = table.getSelectionModel().getSelectedItems();

        productSelected.forEach(productData::remove);
    }

    public ObservableList<Product> productData = FXCollections.observableArrayList(
    new Product("001", "Cereal", "1/1/2017"),
    new Product("002", "Dog Food", "3/3/2017"),
    new Product("003", "Juice", "1/1/2018")
    );


}

非常感谢任何建议。谢谢你的阅读。

1 个答案:

答案 0 :(得分:1)

您有此错误:

  

线程中的异常&#34; JavaFX应用程序线程&#34;   java.lang.UnsupportedOperationException at   java.util.AbstractList.remove(AbstractList.java:161)at   java.util.AbstractList $ Itr.remove(AbstractList.java:374)at   java.util.AbstractCollection.remove(AbstractCollection.java:293)at   application.MainApp.deleteButtonClicked(MainApp.java:297)at   application.MainApp $ 2.handle(MainApp.java:255)at   application.MainApp $ 2.handle(MainApp.java:1)

尝试将productSelected.forEach(productData::remove);替换为:

  productSelected.forEach(this.productData::remove);
                           |

提及您希望从ObservableList而不是FilteredList删除数据,当从ObservableList删除数据时,它会自动从FilteredList<Product>中删除// DELETE BUTTON FUNCTION public void deleteButtonClicked() { table.getSelectionModel().getSelectedItems().forEach(this.productData::remove); }

如果您想用最少的代码编写方法:

from multiselectfield import MultiSelectField

# ...

MY_CHOICES = (('item_key1', 'Item title 1.1'),
          ('item_key2', 'Item title 1.2'),
          ('item_key3', 'Item title 1.3'),
          ('item_key4', 'Item title 1.4'),
          ('item_key5', 'Item title 1.5'))

MY_CHOICES2 = ((1, 'Item title 2.1'),
           (2, 'Item title 2.2'),
           (3, 'Item title 2.3'),
           (4, 'Item title 2.4'),
           (5, 'Item title 2.5'))

class MyModel(models.Model):

    # .....

    my_field = MultiSelectField(choices=MY_CHOICES)
    my_field2 = MultiSelectField(choices=MY_CHOICES2,
                             max_choices=3,
                             max_length=3)