【问题标题】:How can I use user input dates to filter out objects in an array list?如何使用用户输入日期过滤掉数组列表中的对象?
【发布时间】:2022-01-01 01:50:50
【问题描述】:

我在 JavaFX 中有一个 TableView 显示许多对象的属性,代表订单。

Screenshot of sample TableView Output Window

为此,我有一个名为 items 的 ArrayList,其中填充了来自 Item 类的对象。我已经声明了很多这样的对象:

ArrayList items = new ArrayList();
items.add(new Item("01/01/2021", 20, 10, 10, 1));
items.add(new Item("01/21/2021", 15, 5, 10, 2));
items.add(new Item("02/11/2021", 12, 6, 6, 1));
items.add(new Item("03/29/2021", 35, 5, 30, 7));
items.add(new Item("04/14/2021", 16, 16, 0, 0));
items.add(new Item("04/21/2021", 20, 10, 10, 1)); // etc

我想知道是否有一种方法可以利用 2 个用户输入的日期 (MM/dd/yyyy) 在 TableView 上仅显示日期属性在范围之间以匹配对象的对象。我知道我必须删除某些对象才能完全从 TableView 中省略它们,但我不确定如何。例如,如果我们让用户输入日期“01/01/2021”和“04/01/2021”,则表格视图将仅显示上述示例代码中显示的前 4 个项目。

我的用户输入逻辑已经完成,但我希望了解如何在使用两个日期时编辑 ArrayList 本身,以便 TableView 输出过滤后的项目。以下是迄今为止我的代码的简化版本。

主类:

import java.util.ArrayList;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import javafx.event.*;

 
public class Main extends Application  {
    
    Label errorMessage;
    Button button;
    
    
    public static void main(String args[]){          
         launch(args);     
    } 
         
    @Override    
    public void start(Stage primaryStage) throws Exception { 
        
        primaryStage.setTitle("Item Information");
        
        VBox layout = new VBox();
        VBox layout2 = new VBox();
        layout.setAlignment(Pos.CENTER);
        layout2.setAlignment(Pos.CENTER);
        
        // 1st scene is for collecting user input, 2nd scene is outputting the TableView
        Scene scene = new Scene(layout, 500, 500);
        Scene scene2 = new Scene(layout2, 500, 500);
        
        // Code for 1st Scene
        Label label1 = new Label("Report Start Date");
        TextField textField1 = new TextField();
        textField1.setPromptText("mm/dd/yyyy");
        // formatting code

        Label label2 = new Label("Report End Date");
        TextField textField2 = new TextField();
        textField2.setPromptText("mm/dd/yyyy");
        // formatting code
        
        errorMessage= new Label(" ");
        button = new Button("Run Report");
        
        button.setOnAction(e -> validityCheck(textField1, textField1.getText(), primaryStage, scene2));
        button.setOnAction(e -> validityCheck(textField2, textField2.getText(), primaryStage, scene2));
        
        
        // Code for 2nd Scene/TableView
        ObservableList data = getData();
        TableView itemTable = new TableView<>();
        itemTable.prefHeightProperty().bind(primaryStage.heightProperty());
        itemTable.prefWidthProperty().bind(primaryStage.widthProperty());

        TableColumn itemSaleDateCol = new TableColumn("Sale Date");
        TableColumn itemSalePriceCol = new TableColumn("Sale Price");
        TableColumn itemSaleCostCol = new TableColumn("Sale Cost"); 
        TableColumn itemProfitOrLossCol = new TableColumn("Profit or Loss"); 
        TableColumn itemProfitMarginCol = new TableColumn("Profit Margin"); 
        
        
        itemSaleDateCol.setCellValueFactory(new PropertyValueFactory("itemSaleDate"));
        itemSalePriceCol.setCellValueFactory(new PropertyValueFactory("itemSalePrice"));
        itemSaleCostCol.setCellValueFactory(new PropertyValueFactory("itemSaleCost"));
        itemProfitOrLossCol.setCellValueFactory(new PropertyValueFactory("itemProfitOrLoss")); 
        itemProfitMarginCol.setCellValueFactory(new PropertyValueFactory("itemProfitMargin"));
                
        itemTable.setItems(data);
        itemTable.getColumns().addAll(itemSaleDateCol, itemSalePriceCol, itemSaleCostCol, itemProfitOrLossCol, itemProfitMarginCol);

        layout.getChildren().addAll(label1, textField1, label2, textField2, button, label3);
        layout2.getChildren().addAll(itemTable);

        primaryStage.setScene(scene);   
        primaryStage.show();
    }
    
    public static ObservableList getData() {
        // create our data, return an observable list
        // this could be any product data, and could come from anywhere
        // we store our data in an array list, then send that array list to FXCollections.observableArrayList to change it to the necessary collection type
        ArrayList items = new ArrayList();
        // sample items from the order
        items.add(new Item("01/21/2021", 20, 10, 10, 1));
        items.add(new Item("03/02/2021", 15, 5, 10, 2));
        items.add(new Item("06/11/2021", 12, 6, 6, 1));
        items.add(new Item("10/30/2021", 35, 5, 30, 7));
        items.add(new Item("12/14/2021", 16, 16, 0, 0));
        
        return FXCollections.observableArrayList(items);
    }
    
    private boolean validityCheck(TextField input, String message, Stage stage, Scene scene) {
    
        DateTimeFormatter df = DateTimeFormatter.ofPattern("MM/dd/yyyy");
        try {
           LocalDate startDate = LocalDate.parse(message, df);
           stage.setScene(scene);
           return true;
         }
         catch(Exception ex) { 
            errorMessage.setText("Invalid Input(s). Ensure you've typed a VALID date formatted as MM/DD/YYYY.");
            return false;
         }
    }
}

物品类别:

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Item {
    // member variables with "property" data types
    private StringProperty itemSaleDate;
    private IntegerProperty itemSalePrice;
    private IntegerProperty itemSaleCost;
    private IntegerProperty itemProfitOrLoss;
    private IntegerProperty itemProfitMargin;
    
    public Item(String iSd, int iSp, int iSc, int iPoL, int iPm) {
        setItemSaleDate(iSd);
        setItemSalePrice(iSp);
        setItemSaleCost(iSc);
        setItemProfitOrLoss(iPoL);
        setItemProfitMargin(iPm);
    }
    
    // Item Sale Date Property - instantiates itemSaleDate if its null first, then returns it
    public StringProperty itemSaleDateProperty() {
        if (itemSaleDate == null) {
            itemSaleDate = new SimpleStringProperty(this, "itemSaleDate");
        }
        return itemSaleDate;
    }
    // getters and setters
    public void setItemSaleDate(String value) {
        itemSaleDateProperty().set(value);
    }
    public String getItemSaleDate() {
        return itemSaleDateProperty().get();
    }
        
    
    public IntegerProperty itemSalePriceProperty() {
        if (itemSalePrice == null) {
            itemSalePrice = new SimpleIntegerProperty(0);
        }
        return itemSalePrice;
    }
    public void setItemSalePrice(int value) {
        itemSalePriceProperty().set(value);
    }
    public int getItemSalePrice() {
        return itemSalePriceProperty().get();
    }
    
    
    public IntegerProperty itemSaleCostProperty() {
        if (itemSaleCost == null) {
            itemSaleCost = new SimpleIntegerProperty(0);
        }
        return itemSalePrice;
    }
    public void setItemSaleCost(int value) {
        itemSaleCostProperty().set(value);
    }
    public int getItemCostPrice() {
        return itemSaleCostProperty().get();
    }

    
    public IntegerProperty itemProfitOrLossProperty() {
        if (itemProfitOrLoss == null) {
            itemProfitOrLoss = new SimpleIntegerProperty(0);
        }
        return itemProfitOrLoss;
    }
    public void setItemProfitOrLoss(int value) {
        itemProfitOrLossProperty().set(value);
    }
    public int getItemProfitOrLoss() {
        return itemProfitOrLossProperty().get();
    }
    
    
    public IntegerProperty itemProfitMarginProperty() {
        if (itemProfitMargin == null) {
            itemProfitMargin = new SimpleIntegerProperty(0);
        }
        return itemProfitMargin;
    }
    public void setItemProfitMargin(int value) {
        itemProfitMarginProperty().set(value);
    }
    public int getItemProfitMargin() {
        return itemProfitMarginProperty().get();
    }
}

【问题讨论】:

标签: java date javafx arraylist user-input


【解决方案1】:

首先,定义您的自定义类以采用LocalDate 对象而不是字符串。

record Item ( LocalDate when , int code ) {}

用法。

List < Item > items = 
    List.of( 
        new Item( LocalDate.of( 2022 , Month.JANUARY ,  23 ) , 10 ) ,
        new Item( LocalDate.of( 2022 , Month.FEBRUARY ,  24 ) , 11 ) ,
        new Item( LocalDate.of( 2022 , 3 ,  25 ) , 12 )
    )
;

定义您的日期范围。

LocalDate start = LocalDate.of( 2022 , 2 , 1 ) ;
LocalDate end = start.plusMonths( 1 ) ;

循环你的列表,检查每一个是否匹配。

List< Item > hits = new ArrayList <> () ;
for( Item item : items ) {
    if( ( ! item.when.isBefore( start ) ) && item.when.isBefore( end ) ) {
        hits.add( item ) ;
    }
}

或者使用流和 lambdas。

List< Item > hits = items.stream().filter( item -> ( ! item.when.isBefore( start ) ) && item.when.isBefore( end ) ).toList() ;

如果您要编写大部分代码,我建议将 ThreeTen-Extra 库添加到您的项目中,以使用 LocalDateRange 类。

【讨论】:

  • 我注意到你把“LocalDate end = start.plusMonths(1);”定义日期范围时。这是否意味着结束过滤器必须是整数,例如开始日期后 1 个月?如果是这样,有没有办法可以使用特定的结束日期,比如开始值?
  • 正如我之前已经建议的:公开显示代码时请遵守 java 编码/格式约定
  • @jcpark 当然你可以设置任何你想要的结束日期。
  • @kleopatra 你指的是什么约定?
  • @BasilBourque 感谢您的澄清。 .plusMonths() 在示例代码中算什么?我可以用 LocalDate.of() 代替它吗?
【解决方案2】:

您可以使用 java 库中的 SimpleDateFormat 类并以特定格式从用户那里获取日期

尝试运行我的这段代码以更好地理解该类。

以dd/mm/yyyy格式获取日期并以yyyy mm dd格式显示

public class DateTime {

static void Condate(String inputDate) {
    try {
        
        SimpleDateFormat sfd=new SimpleDateFormat("dd/mm/yyyy");
        //String t=sfd.format();
        Date date=sfd.parse(inputDate);
        SimpleDateFormat outputsfd=new SimpleDateFormat("yyyy mm dd");
        String outputdate=outputsfd.format(date);
        System.out.println("after changing the date to yyyy/mm/dd : "+outputdate);
        
    }catch(java.text.ParseException e){
        System.out.println("error occured");
    }
}   

public static void main(String[] args) {
    Scanner r=new Scanner(System.in);
    System.out.println("enter date is dd/mm/yyyy : ");
    String d=r.nextLine();
    Condate(d); 
    r.close();
}

【讨论】:

  • 您正在使用 terrible 日期时间类,这些类在几年前被 JSR 310 中定义的现代 java.time 类所取代。
猜你喜欢
  • 1970-01-01
  • 2018-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 1970-01-01
  • 2022-09-23
相关资源
最近更新 更多