2016-12-01 2 views
2

Hallo, dies ist meine erste Frage als Neuling in Java und GUI-Design. Ich bin auf eine merkwürdige Situation gestoßen, die ich gerade sehe. Ich habe TableView mit einigen Informationen, die auch mit der Schaltfläche Hinzufügen hinzugefügt werden können. Die Löschen-Schaltfläche funktionierte vor dem Hinzufügen eines FilterList-Konstruktors, sodass ich die Suchergebnisse nach ID filtern konnte. Sobald ich die Funktion hinzugefügt habe, funktioniert die Schaltfläche Löschen nicht mehr. Ich persönlich denke, dass die deleteButtonClicked-Klasse die Tabelle aufgrund der Änderung durch Hinzufügen der Filter-Funktionalität nicht mehr richtig erkennt. Aber so sehr ich versuche, beides zu behalten, hört der eine oder andere normalerweise auf zu arbeiten. Ich versuche derzeit, es ohne eine Delete Button-Klasse funktionieren zu lassen, vielleicht indem ich das Produkt einfach null mache.JavaFX GUI - Warum funktioniert die Delete Button Funktion nicht mit dem TableView?

Die TableView-Funktionen befinden sich oben im Code, während die Löschschaltfläche und die Funktionen nach unten zeigen.

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") 
    ); 


} 

Alle Vorschläge werden sehr geschätzt. Danke fürs Lesen.

Antwort

1

Sie haben diesen Fehler:

Exception in thread "JavaFX Application Thread" 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)

Versuchen productSelected.forEach(productData::remove); mit dem Ersetzen:

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

Erwähnung, dass Sie die Daten aus dem ObservableList nicht die FilteredList, entfernen möchten beim Entfernen Sie werden von der ObservableList automatisch aus th entfernt e FilteredList<Product>


Wenn Sie möchten, dass Sie Methode mit minimalem Code schreiben:

// DELETE BUTTON FUNCTION 
    public void deleteButtonClicked() { 
    table.getSelectionModel().getSelectedItems().forEach(this.productData::remove); 
    } 
+0

Wow danke, dass und eine sehr einfache Lösung gearbeitet zu. Hat "das" getan. arbeiten, weil es direkt auf das aktuelle Objekt verweist? Wollen Sie in einfachen Worten erklären, warum es in dieser Situation benötigt wird? Weil, wie ich erklärte, es ohne vorher gut funktioniert hat, das ist das, was mich verwirrt hat. Danke noch einmal. – BecauseTurtles

+0

@BecauseTurtles Bevor Sie in Ihrem Code '.getItems()' verwenden, haben Sie die 'FilteredList ' zurückbekommen und versucht, Elemente daraus zu entfernen. Aber die 'FilteredList ' hat ursprünglich die Elemente der 'ObservableList', also Sie möchten die Objekte aus der "ObservableList" entfernen. Dadurch werden sie automatisch aus der 'FilteredList ' entfernt. Ich benutze 'this', um auf die äußere' ObservableList' zu verweisen. – GOXR3PLUS