javaswinglinked-listjtableabstracttablemodel

GUI Not working with custom AbstractTableModel. Errors "Unknown Source"


I am currently creating, or more trying to create the GUI for my project. What I need to do now, is create a JTable that reads the data from a LinkedList. I have a custom TableAbstractModel for this.

public class StudentTableModel extends AbstractTableModel {

public static final String[] columnNames = { "ID", "First Name",
        "Last Name" };
private LinkedList<Student> data;

public StudentTableModel(LinkedList<Student> data) {
    this.data = data;
}

@Override
public int getColumnCount() {
    return columnNames.length;
}

@Override
public String getColumnName(int column) {
    return columnNames[column];
}

@Override
public int getRowCount() {
    return data.size();
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    Student student = data.get(rowIndex);
    if (student == null) {
        return null;
    }
    switch (columnIndex) {
    case 0:
        return student.getID();
    case 1:
        return student.getFirstname();
    case 2:
        return student.getLastname();
    default:
        return null;
    }
}

}

Now I was trying to build a very basic layout consisting just of the table, and the appropriate JTextfields and JButtons to test if the table actually works.

public class GUI extends JFrame {

private JTextField StudentID;
private JTextField Firstname;
private JTextField Lastname;
private JTextField Group;
private JButton Add;
private static Database DB; // << Does this have to be static? Eclipse tells me it needs to be, but I am not sure.
private JTable StudentTable;

public GUI(Database DB) {
    super("Theatre Management");
    setExtendedState(JFrame.MAXIMIZED_BOTH);
    this.DB = DB;
    LinkedList<Student> data = null;

    setLayout(new FlowLayout());
    StudentID = new JTextField("Enter Student ID", 10);
    Firstname = new JTextField("Enter First Name");
    Lastname = new JTextField("Enter Last Name");
    Group = new JTextField("Enter Group ID");
    Add = new JButton("Add Student");
    StudentTable = new JTable();
    StudentTable.setModel(new StudentTableModel(data));
    JScrollPane scrollPane = new JScrollPane(StudentTable);
    StudentTable.setFillsViewportHeight(true);

    add(StudentTable);
    add(StudentID);
    add(Firstname);
    add(Lastname);
    add(Group);
    add(Add);
    add(scrollPane);

    addStudentEvent add = new addStudentEvent();
    Add.addActionListener(add);

}

public static void createAndShow() {
    GUI Database = new GUI(DB);
    Database.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    Database.setVisible(true);

}

public static void main(String[] args) {
    GUI.createAndShow();

}

private class addStudentEvent implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        int G = Integer.parseInt(Group.getText());
        int ID = Integer.parseInt(StudentID.getText());
        String First = Firstname.getText();
        String Last = Lastname.getText();

        DB.getGroup(G).addStudent(ID, First, Last);
        DB.addStudent(ID, First, Last);
    }

}

}

Now, the problem is, as soon as I try to run the GUI, I just get a whole bunch of errors.

Exception in thread "main" java.lang.NullPointerException
at theatremanagement.StudentTableModel.getRowCount(StudentTableModel.java:29)
at javax.swing.JTable.getRowCount(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.createTableSize(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at java.awt.FlowLayout.layoutContainer(Unknown Source)
at java.awt.Container.layout(Unknown Source)
at java.awt.Container.doLayout(Unknown Source)
at java.awt.Container.validateTree(Unknown Source)
at java.awt.Container.validateTree(Unknown Source)
at java.awt.Container.validateTree(Unknown Source)
at java.awt.Container.validateTree(Unknown Source)
at java.awt.Container.validate(Unknown Source)
at java.awt.Container.validateUnconditionally(Unknown Source)
at java.awt.Window.show(Unknown Source)
at java.awt.Component.show(Unknown Source)
at java.awt.Component.setVisible(Unknown Source)
at java.awt.Window.setVisible(Unknown Source)
at theatremanagement.GUI.createAndShow(GUI.java:59)
at theatremanagement.GUI.main(GUI.java:64)

I am really stuck right now and have no clue how to fix that. If anybody could show me what I am doing wrong, that would be great. On other thing, I have to LinkedList in my program, in different classes. How does the TableModel know which one I want? Do I need to add anything to the TableModel, to make the table automatically update as soon as a add or delete a student?

Update:

private JTable setStudentList(LinkedList<Student> Studentlist) {
    JTable StudentTable = new JTable();
    StudentTable.setModel(new StudentTableModel(Studentlist));
    JScrollPane scrollPane = new JScrollPane(StudentTable);
    StudentTable.setFillsViewportHeight(true);
    return StudentTable;

Does this method work to create the table with the linked list? Would I then call for the method as

setStudentList(Studentlist); 

If I initiliazed an empty LinkedList as such:

LinkedList<Student> StudentList = new LinkedList<Student>();

Thanks for the help.


Solution

  • The LinkedList is never initalised...

    LinkedList<Student> data = null;
    // ... ///
    StudentTable.setModel(new StudentTableModel(data));
    

    Meaning that when getRowCount is called, the data object is null, hence the NullPointerException

    Updated

    You have any number of options that you can use to pass a reference to main LinkedList into the UI, but it will come down to how your work flow works.

    You could...

    Pass the reference to the UI via it's constructor....

    public GUI(Database DB, LinkedList<Student> students) {...}
    

    You could...

    Pass the LinkedList in via a method in you GUI class...

    public class GUI extends JFrame {
    
        //...//
    
        public GUI(Database DB) {...}
    
        public void setStudent(LinkedList<Student> students) {
            StudentTable.setModel(new StudentTableModel(students));
        }
    }
    

    Updated with example

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.LinkedList;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.AbstractTableModel;
    
    public class PassTable {
    
        public static void main(String[] args) {
            new PassTable();
        }
    
        public PassTable() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Test");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
    
            });
        }
    
        public class TestPane extends JPanel {
    
            private ExampleTable example;
    
            public TestPane() {
                setLayout(new BorderLayout());
                example = new ExampleTable();
                add(example);
                JButton add = new JButton("Add");
                add(add, BorderLayout.SOUTH);
                add.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        LinkedList<Person> people = new LinkedList<Person>();
                        people.add(new Person("A", "A", 1));
                        people.add(new Person("B", "B", 2));
                        people.add(new Person("C", "C", 3));
                        people.add(new Person("D", "D", 4));
                        example.setPeople(people);
                    }
                });
            }
    
        }
    
        public class ExampleTable extends JPanel {
    
            private JTable table;
    
            public ExampleTable() {
                this(new LinkedList<Person>());
            }
    
            public ExampleTable(LinkedList<Person> people) {
                setLayout(new BorderLayout());
                table = new JTable(new SampleTableModel(people));
                add(new JScrollPane(table));
            }
    
            public void setPeople(LinkedList<Person> people) {
                table.setModel(new SampleTableModel(people));
            }
    
        }
    
        public class SampleTableModel extends AbstractTableModel {
    
            private LinkedList<Person> data;
    
            public SampleTableModel(LinkedList<Person> data) {
                this.data = data;
            }
    
            @Override
            public int getRowCount() {
                return data.size();
            }
    
            @Override
            public String getColumnName(int column) {
                String name = "";
                switch (column) {
                    case 0:
                        name = "First name";
                        break;
                    case 1:
                        name = "Last name";
                        break;
                    case 2:
                        name = "Age";
                        break;
                }
                return name;
            }
    
            @Override
            public int getColumnCount() {
                return 3;
            }
    
            @Override
            public Object getValueAt(int rowIndex, int columnIndex) {
                Object value = null;
                Person person = data.get(rowIndex);
                switch (columnIndex) {
                    case 0:
                        value = person.getFirstName();
                        break;
                    case 1:
                        value = person.getLastName();
                        break;
                    case 2:
                        value = person.getAge();
                        break;
                }
                return value;
            }
    
        }
    
        public class Person {
            private String firstName;
            private String lastName;
            private int age;
    
            public Person(String firstName, String lastName, int age) {
                this.firstName = firstName;
                this.lastName = lastName;
                this.age = age;
            }
    
            public int getAge() {
                return age;
            }
    
            public String getFirstName() {
                return firstName;
            }
    
            public String getLastName() {
                return lastName;
            }
    
        }
    
    }