0

I'm working on a larger project (together with quite a number of fellow students), and I'm trying to display an arrayList (which type we're using over and over again in our project, so I wouldn't love to change all these to ObservableLists just for my rather small issue) in a TableView.

I've created a smaller project just in order to get to the heart of the problem and to show you:

In the class editMyGrades (together with an fxml file of the same name) I want to display my SUBJECTs (-> String subjectName), each one with its GRADE (-> int grade) in a TableView.

Initializing the parent root and the tableView the ArrayList subjects is transformed to an ObservableList, which is loaded into the TableView.

I really would like to understand theoretically, why changing GRADEs works with the tableView, but removing doesn't, and to know what to do about it practically ;-)

Thank you very much in advance!

Main class:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.util.ArrayList;

public class Main extends Application {
    private static ArrayList<Subject> subjects = new ArrayList<>();
    public static ArrayList<Subject> getSubjects () {return subjects;}

//    private static ObservableList<Subject> subjects = FXCollections.observableArrayList();
//    public static ObservableList<Subject> getSubjects () {return subjects;}


    public static void main (String[] args) {

        subjects.add(new Subject("computer science", 2));
        subjects.add(new Subject("literature", 4));

        launch (args);
    }

    public void start (Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/editMyGrades.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Class Subject:

public class Subject {
    private String subjectName;
    private int grade;

    public Subject (String subjectName, int grade) {
        this.subjectName = subjectName;
        this.grade = grade;
    }

    public String getSubjectName () {return subjectName;}

    public int getGrade () {return grade;}

    public void setGrade (int grade) {this.grade = grade;}


}

controlling class editMyGrades:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;

import java.util.ArrayList;

public class editMyGrades {

    Subject subjectToEdit;

    @FXML
    private TableView<Subject> tableView;

    @FXML
    private TableColumn<Subject, String> subjectCol;

    @FXML
    private TableColumn<Subject, Number> gradeCol;

    @FXML
    private TextField textField;

    @FXML
    private Button changeButton;

    @FXML
    private Button deleteButton;

    @FXML
    public void initialize() {
        subjectCol.setCellValueFactory(new PropertyValueFactory<>("subjectName"));
        gradeCol.setCellValueFactory(new PropertyValueFactory<>("grade"));

        //tableView.setItems (FXCollections.observableArrayList(Main.getSubjects()));
        ObservableList<Subject> subjects = FXCollections.observableArrayList(Main.getSubjects());
        tableView.setItems(subjects);
    }

    @FXML
    private void tableViewClicked(MouseEvent event) {
        if (event.getClickCount() == 2) {
            subjectToEdit = tableView.getSelectionModel().getSelectedItem();
            textField.setText ("" + tableView.getSelectionModel().getSelectedItem().getGrade());
        }
    }

    @FXML
    private void change(ActionEvent event) {
        subjectToEdit.setGrade(Integer.parseInt(textField.getText()));
        textField.clear();

        tableView.refresh();
    }

    @FXML
    private void delete (ActionEvent event) {
        Subject selectedSubject = tableView.getSelectionModel().getSelectedItem();
        ArrayList<Subject> subjects = Main.getSubjects();
        subjects.remove(selectedSubject);

        tableView.refresh();
    }

}

editingMyGrades.fxml:

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

<?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.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="editMyGrades">
   <children>
      <Label text="change your grades!" />
      <HBox>
         <children>
            <TableView fx:id="tableView" onMouseClicked="#tableViewClicked" prefHeight="200.0" prefWidth="518.0">
              <columns>
                <TableColumn fx:id="subjectCol" prefWidth="262.0" text="subject" />
                <TableColumn fx:id="gradeCol" minWidth="0.0" prefWidth="146.0" text="grade" />
              </columns>
            </TableView>
            <VBox alignment="CENTER">
               <children>
                  <Button mnemonicParsing="false" onAction="#delete" text="deleteButton" />
               </children>
            </VBox>
         </children>
      </HBox>
      <TextField fx:id="textField" maxWidth="100.0" />
      <Button fx:id="changeButton" mnemonicParsing="false" onAction="#change" text="Change!" />
   </children>
</VBox>
  • 1
    only skimming the code (it's not _Minimal_ :) - a) it's wrong to call table.refresh in the general case, if it appears to be needed it's an indication of something wrong in wiring/setup! b) don't use static scope! c) java naming conventions, please – kleopatra Jan 08 '21 at 13:35
  • the error is that you remove the subject from the list in Main (see last comment - static scope is wrong :) - you should it remove it from the table's items – kleopatra Jan 08 '21 at 13:40
  • Thank you! I always try to follow the conventions learnt from my teachers. Where should I have used other names? – MagisterInformaticus Jan 08 '21 at 13:42
  • class names must start with a capital letter – kleopatra Jan 08 '21 at 13:43
  • Two more questions: if I shall not use static at all, it follows that I never put any attributes and accessors there either (to avoid the static scope), right? +++ If I understand you properly, I have to remove the items from the tableView itself? Via google I haven't found a command to do that. – MagisterInformaticus Jan 08 '21 at 13:57
  • (I've put the stuff in the Main to be able to access it throughout the entire program. How would you manage something like that without linking it in any way with the Main class?) – MagisterInformaticus Jan 08 '21 at 14:00
  • 2
    Create a data model and pass it to the controller. See, for example, https://stackoverflow.com/questions/32342864/applying-mvc-with-javafx – James_D Jan 08 '21 at 14:24

2 Answers2

0

When working with JavaFX it's good practice to always use FXCollections.

When you make a modification to the ArrayList, the changes are not generating list change nofications. You must get the ObservableList from the tableview and perform the operations on it since it is the wrapper (the smart list) that is backed by your ArrayList.

0

Thank you indeed for your explanations! In fact in my real problem I'm using MVC, but the Controller object is located in the main - static -, and as it appears, it can't be done in other way. For the illustration of my problem I thought id wouldn't make a difference, if I had a static controller object with the list or just the list itself (perhaps I was wrong ...). Now, having tried to apply everything you told me, it's just the other way around: the tableView displays removements, but no changes.

just the fxml control class EditMyGrades:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;


public class EditMyGrades {

    private ObservableList<Subject> subjects = FXCollections.observableArrayList();

    private Subject subjectToEdit;

    @FXML
    private TableView<Subject> tableView;

    @FXML
    private TableColumn<Subject, String> subjectCol;

    @FXML
    private TableColumn<Subject, Number> gradeCol;

    @FXML
    private TextField textField;

    @FXML
    private Button changeButton;

    @FXML
    private Button deleteButton;

    @FXML
    public void initialize() {
        subjectCol.setCellValueFactory(new PropertyValueFactory<>("subjectName"));
        gradeCol.setCellValueFactory(new PropertyValueFactory<>("grade"));

        subjects.add(new Subject("computer science", 2));
        subjects.add(new Subject("literature", 4));

        tableView.setItems(subjects);
    }

    @FXML
    private void tableViewClicked(MouseEvent event) {
        if (event.getClickCount() == 2) {
            subjectToEdit = tableView.getSelectionModel().getSelectedItem();
            textField.setText ("" + tableView.getSelectionModel().getSelectedItem().getGrade());
        }
    }

    @FXML
    private void change(ActionEvent event) {
        subjectToEdit.setGrade(Integer.parseInt(textField.getText()));
        textField.clear();
    }

    @FXML
    private void delete (ActionEvent event) {
        ObservableList<Subject> subjects = tableView.getItems();
        Subject selectedSubject = tableView.getSelectionModel().getSelectedItem();
        subjects.remove(selectedSubject);
    }

}
  • hmm .. is this an answer or a modification of the question? If the former, clarify what/how exactly it solves, if the latter edit the question instead – kleopatra Jan 08 '21 at 23:10