-1

I am making a to do list with java FXML using file reader and writer and scene builder. I have been trying to add a completed task function but tried many ways and am unable to figure out something which will work for me. I tried making a separate list where I keep my completed task but its still not working out for me. At this moment I have tried a lot by myself and am willing to go for another for another method to add this function. I am using To Do Date Class which is using to do Item class. I have tried using it as predicate of filtered list and type casting accordingly but it hasn't worked out for me either.Rest of code works perfectly fine. controller is:

package todolist;

import java.io.IOException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Predicate;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.util.Callback;

/**
 *
 * @author Pc Planet
 */
public class FXMLDocumentController {
    
   private List<ToDoItem> todoItems;

    @FXML
    private ListView<ToDoItem> todoListView;

    @FXML
    private TextArea itemDetailsTextArea;

    @FXML
    private Label deadlineLabel;

    @FXML
    private BorderPane mainBorderPane;

    @FXML
    private ContextMenu listContextMenu;

    @FXML
    private ToggleButton filterToggleButton;
    @FXML
    private Button exit,ADD;

    private FilteredList<ToDoItem> filteredList;

    private Predicate<ToDoItem> wantAllItems;
    private Predicate<ToDoItem> wantTodaysItems;


    private Predicate<ToDoItem> uncompleted;
    private ObservableList<ToDoItem> completed;

    public void initialize() {
// delete
        listContextMenu = new ContextMenu();
        MenuItem deleteMenuItem = new MenuItem("Delete");
        deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
                deleteItem(item);
            }
        });

// Completed
        listContextMenu = new ContextMenu();
        MenuItem completedMenuItem = new MenuItem("Mark as complete");
        completedMenuItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
                completedItem(item);
            }
        });
listContextMenu.getItems().addAll(deleteMenuItem);
listContextMenu.getItems().addAll(completedMenuItem);

//change
  
        todoListView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ToDoItem>() {
            @Override
            public void changed(ObservableValue<? extends ToDoItem> observable, ToDoItem oldValue, ToDoItem newValue) {
                if(newValue != null) {
                    ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
                    itemDetailsTextArea.setText(item.getDetails());
                    DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM d, yyyy"); // "d M yy");
                    deadlineLabel.setText(df.format(item.getDeadline()));
                }
            }
        });

        wantAllItems = (ToDoItem todoItem) -> true;
          
        wantTodaysItems = (ToDoItem todoItem) -> (todoItem.getDeadline().equals(LocalDate.now()));


        filteredList = new FilteredList<ToDoItem>(ToDoData.getInstance().getTodoItems(), wantAllItems);

        
// list sort
        SortedList<ToDoItem> sortedList = new SortedList<ToDoItem>(filteredList,
                new Comparator<ToDoItem>() {
                    @Override
                    public int compare(ToDoItem o1, ToDoItem o2) {
                        return o1.getDeadline().compareTo(o2.getDeadline());
                    }
                });


        todoListView.setItems(sortedList);

        todoListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
        todoListView.getSelectionModel().selectFirst();

        todoListView.setCellFactory(new Callback<ListView<ToDoItem>, ListCell<ToDoItem>>() {
            @Override
            public ListCell<ToDoItem> call(ListView<ToDoItem> param) {
                ListCell<ToDoItem> cell = new ListCell<ToDoItem>() {

                    @Override
                    protected void updateItem(ToDoItem item, boolean empty) {
                        super.updateItem(item, empty);
                        if(empty) {
                            setText(null);
                        } else {
                            setText(item.getShortDescription());
                            if(item.getDeadline().isBefore(LocalDate.now().plusDays(1))) {
                                setTextFill(Color.RED);
                            } else  {
                                setTextFill(Color.GREEN);
                            }
                            
                        }
                    }
                };

                cell.emptyProperty().addListener(
                        (obs, wasEmpty, isNowEmpty) -> {
                            if(isNowEmpty) {
                                cell.setContextMenu(null);
                            } else {
                                cell.setContextMenu(listContextMenu);
                            }
                });

                return cell;
            }
        });
    }

    @FXML
    public void showNewItemDialog() {
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.initOwner(mainBorderPane.getScene().getWindow());
        dialog.setTitle("Add New Todo Item");
        dialog.setHeaderText("Use this dialog to create a new todo item");
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("todoitemdialog.fxml"));
        try {
            dialog.getDialogPane().setContent(fxmlLoader.load());

        } catch(IOException e) {
            System.out.println("Couldn't load the dialog");
            e.printStackTrace();
            return;
        }

        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
        dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);

        Optional<ButtonType> result = dialog.showAndWait();
        if(result.isPresent() && result.get() == ButtonType.OK) {
            DialogController controller = fxmlLoader.getController();
            ToDoItem newItem = controller.processResults();
            todoListView.getSelectionModel().select(newItem);
        }


    }
    @FXML
    public void completedtasks(ActionEvent event){
      

}
    @FXML
    public void handleKeyPressed(KeyEvent keyEvent) {
        ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
        if(selectedItem != null) {
            if(keyEvent.getCode().equals(KeyCode.DELETE)) {
                deleteItem(selectedItem);}
             else{
                completedItem(selectedItem);
            }
        }
    }
    
   
    
    public void handleClickListView() {
        ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
        itemDetailsTextArea.setText(item.getDetails());
        deadlineLabel.setText(item.getDeadline().toString());
    }

    public void deleteItem(ToDoItem item) {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("Delete Todo Item");
        alert.setHeaderText("Delete item: " + item.getShortDescription());
        alert.setContentText("Are you sure?  Press OK to confirm or cancel to Back out.");
        Optional<ButtonType> result = alert.showAndWait();

        if(result.isPresent() && (result.get() == ButtonType.OK)) {
            ToDoData.getInstance().deleteTodoItem(item);
        }

    }
 
        public void completedItem(ToDoItem item) {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("Mark as Completed");
        alert.setHeaderText("Completed task: " + item.getShortDescription());
        alert.setContentText("Are you sure?  Press OK to confirm or cancel to Back out.");
        Optional<ButtonType> result = alert.showAndWait();

        if(result.isPresent() && (result.get() == ButtonType.OK)) {
            ToDoData.getInstance().completed(item);
        }

    }    
@FXML
   public void wantTodaysItems(){
          ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
          filteredList.setPredicate(wantTodaysItems);
              if(filteredList.isEmpty()) {
                itemDetailsTextArea.clear();
                deadlineLabel.setText("");
            } else if(filteredList.contains(selectedItem)) {
                todoListView.getSelectionModel().select(selectedItem);
            } else {
                todoListView.getSelectionModel().selectFirst();
            }

}

@FXML
    public void wantAllItems(){
     ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
      filteredList.setPredicate(wantAllItems);
     if(filteredList.isEmpty()) {
                itemDetailsTextArea.clear();
                deadlineLabel.setText("");
            } else if(filteredList.contains(selectedItem)) {
                todoListView.getSelectionModel().select(selectedItem);
            } else {
                todoListView.getSelectionModel().selectFirst();
            }
}

    @FXML
    public void handleExit() {
        Platform.exit();

    }
}

ToDoData class is:

package todolist;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;


public class ToDoData {
    private static ToDoData instance = new ToDoData();
    private static String filename = "TodoListItems.txt";

    private ObservableList<ToDoItem> todoItems;
    private ObservableList<ToDoItem> completed;
    private DateTimeFormatter formatter;

    public static ToDoData getInstance() {
        return instance;
    }

    private ToDoData() {
        formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    }

    public ObservableList<ToDoItem> getTodoItems() {
        return todoItems;
    }

    public void addTodoItem(ToDoItem item) {
        todoItems.add(item);
    }
    
    public void loadTodoItems() throws IOException {

        todoItems = FXCollections.observableArrayList();
        Path path = Paths.get(filename);
        BufferedReader br = Files.newBufferedReader(path);

        String input;

        try {
            while ((input = br.readLine()) != null) {
                String[] itemPieces = input.split("\t");

                String shortDescription = itemPieces[0];
                String details = itemPieces[1];
                String dateString = itemPieces[2];

                LocalDate date = LocalDate.parse(dateString, formatter);
                ToDoItem todoItem = new ToDoItem(shortDescription, details, date);
                todoItems.add(todoItem);
            }

        } finally {
            if(br != null) {
                br.close();
            }
        }
    }

    public void storeTodoItems() throws IOException {

        Path path = Paths.get(filename);
        BufferedWriter bw = Files.newBufferedWriter(path);
        try {
            Iterator<ToDoItem> iter = todoItems.iterator();
            while(iter.hasNext()) {
                ToDoItem item = iter.next();
                bw.write(String.format("%s\t%s\t%s",
                        item.getShortDescription(),
                        item.getDetails(),
                        item.getDeadline().format(formatter)));
                bw.newLine();
            }

        } finally {
            if(bw != null) {
                bw.close();
            }
        }
    }

    public void deleteTodoItem(ToDoItem item) {
        todoItems.remove(item);
    }
  

   public void completed(ToDoItem item){
      completed.add(item); 
       
}
 public ObservableList <ToDoItem>  completed(){
     return completed;

       
}
}

todoItem class is:

package todolist;

import java.time.LocalDate;

public class ToDoItem {
    private String shortDescription;
    private String details;
    private LocalDate deadline;

    public ToDoItem(String shortDescription, String details, LocalDate deadline) {
        this.shortDescription = shortDescription;
        this.details = details;
        this.deadline = deadline;
}

    public String getShortDescription() {
        return shortDescription;
    }

    public void setShortDescription(String shortDescription) {
        this.shortDescription = shortDescription;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public LocalDate getDeadline() {
        return deadline;
    }

    public void setDeadline(LocalDate deadline) {
        this.deadline = deadline;
    }

}
zahra
  • 29
  • 3
  • 1
    Consider [_Adding a CheckBox column to an existing TableView_](https://stackoverflow.com/q/68969222/230513) or one of the approaches seen [here](https://stackoverflow.com/q/69711881/230513). – trashgod Jul 25 '22 at 16:24
  • 1
    [mcve] please - focused on exactly _one_ problem – kleopatra Jul 25 '22 at 17:21
  • 2
    Can’t you just add a `BooleanProperty completed` field (and corresponding methods) to the `ToDoItem` class? – James_D Jul 25 '22 at 18:06
  • i tried that way ,it seems better now but it has an error now whose solution i cant find even repeated tries https://stackoverflow.com/questions/73114312/adding-completed-task-function-in-to-do-list-in-java-fxml – zahra Jul 25 '22 at 19:18
  • 1
    [This example](https://stackoverflow.com/questions/25347347/how-to-add-listener-to-the-checkbox-inside-a-listview-that-uses-checkboxlistcell/25347833#25347833) uses similar ideas to that from trashgod (but usesCheckBoxListCell instead of a checkbox in a tableview and also James' idea of a property to keep track of the checkbox state in item class (the example I linked uses the property for selection, but you can change the name to completed for that functionality and it will be similar). – jewelsea Jul 25 '22 at 19:25

1 Answers1

1

This answer is assuming I understand you correctly. In this example, I use a FilteredList on the TableView, and I used the FilteredList's Predicate to show the data in the TableView based on the Button that is pressed. I altered the answer from here.

KeyCode 1

This code allows the TableView to update when the CheckBox values changes.

todoItem ->  new Observable[] { todoItem.completeProperty()}

Key Code 2

This code allows the FilteredList to set the TableView's data based on the Button that is pressed.

flToDoItems.setPredicate((todoItem) -> {
    return todoItem.getComplete();
});

Main

import java.time.LocalDate;
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application
{
    final TableView<ToDoItem> selectionTableView = new TableView<>();
    private final ObservableList<ToDoItem> toDoItems = FXCollections.observableList(
            Arrays.asList(
                    new ToDoItem("Task 1", "This is Task 1", LocalDate.now().plusMonths(1)),
                    new ToDoItem("Task 2", "This is Task 2", LocalDate.now().plusMonths(2)),
                    new ToDoItem("Task 3", "This is Task 3", LocalDate.now().plusMonths(3)),
                    new ToDoItem("Task 4", "This is Task 4", LocalDate.now().plusMonths(4)),
                    new ToDoItem("Task 5", "This is Task 5", LocalDate.now().plusMonths(5))
            ),
            todoItem ->  new Observable[] { todoItem.completeProperty()}//This is needed for automatic updates in the TableView!!!!
    );
    final FilteredList<ToDoItem> flToDoItems = new FilteredList(toDoItems, p -> true);
    
    public static void main(String[] args)
    {
        launch();
    }
        
    @Override
    public void start(Stage stage)
    {
        final TableView<ToDoItem> todoListSelectionTableView = createTodoListSelectionTableView();
        todoListSelectionTableView.setItems(flToDoItems);
        
        Button btnAllTasks = new Button("All");
        btnAllTasks.setOnAction((t) -> {
            flToDoItems.setPredicate((todoItem) -> {
                return true;
            });
        });
        Button btnCompleteTasks = new Button("Complete");
        btnCompleteTasks.setOnAction((t) -> {
            flToDoItems.setPredicate((todoItem) -> {
                return todoItem.getComplete();
            });
        });
        Button btnIncompleteTask = new Button("Incomplete");        
        btnIncompleteTask.setOnAction((t) -> {
            flToDoItems.setPredicate((todoItem) -> {
                return !todoItem.getComplete();
            });
        });
        
        VBox root = new VBox(new HBox(btnAllTasks, btnIncompleteTask, btnCompleteTasks), todoListSelectionTableView);
       
        Scene scene = new Scene(root, 500, 500);
        stage.setScene(scene);
        stage.show();
    }
    
    
    
    private TableView<ToDoItem> createTodoListSelectionTableView() {
        
        selectionTableView.setPrefSize(440, 180);

        TableColumn<ToDoItem, String> shortDescriptionColumn = new TableColumn<>("Short Description");
        shortDescriptionColumn.setCellValueFactory(cd -> cd.getValue().shortDescriptionProperty());
        selectionTableView.getColumns().add(shortDescriptionColumn);

        TableColumn<ToDoItem, String> detailsColumn = new TableColumn<>("Details");
        detailsColumn.setCellValueFactory(cd -> cd.getValue().detailsProperty());
        selectionTableView.getColumns().add(detailsColumn);

        TableColumn<ToDoItem, LocalDate> deadlineColumn = new TableColumn<>("Deadline");
        deadlineColumn.setCellValueFactory(cd -> cd.getValue().deadlineProperty());        
        selectionTableView.getColumns().add(deadlineColumn);

        TableColumn<ToDoItem, Boolean> completeColumn = new TableColumn<>("Complete");
        completeColumn.setCellValueFactory(cd -> cd.getValue().completeProperty());
        completeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(completeColumn));
        selectionTableView.getColumns().add(completeColumn);

        selectionTableView.setEditable(true);
        
        return selectionTableView;
    }
}

ToDoItem

import java.time.LocalDate;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ToDoItem {
    private final StringProperty shortDescription;
    private final StringProperty details;
    private final ObjectProperty<LocalDate> deadline;
    private final BooleanProperty complete;
    
    public ToDoItem(String shortDescription, String details, LocalDate deadline) {
        this.shortDescription = new SimpleStringProperty(shortDescription);
        this.details = new SimpleStringProperty(details);
        this.deadline = new SimpleObjectProperty(deadline);
        this.complete = new SimpleBooleanProperty(false);
}

    public String getShortDescription() {
        return shortDescription.get();
    }

    public void setShortDescription(String shortDescription) {
        this.shortDescription.set(shortDescription);
    }
    
    public StringProperty shortDescriptionProperty()
    {
        return this.shortDescription;
    }

    public String getDetails() {
        return details.get();
    }

    public void setDetails(String details) {
        this.details.set(details);
    }

    public StringProperty detailsProperty()
    {
        return this.details;
    }
    
    public LocalDate getDeadline() {
        return deadline.get();
    }

    public void setDeadline(LocalDate deadline) {
        this.deadline.set(deadline);
    }

    public ObjectProperty<LocalDate> deadlineProperty()
    {
        return this.deadline;
    }
    
    public void setComplete(boolean complete)
    {
        this.complete.set(complete);
    }
    
    public boolean getComplete()
    {
        return this.complete.get();
    }
    
    public BooleanProperty completeProperty()
    {
        return this.complete;
    }
}

Output

enter image description here

SedJ601
  • 12,173
  • 3
  • 41
  • 59