Графический интерфейс не работает с пользовательской AbstractTableModel. Ошибки неизвестного источника

В настоящее время я создаю или больше пытаюсь создать графический интерфейс для своего проекта. Теперь мне нужно создать JTable, который считывает данные из LinkedList. Для этого у меня есть собственная модель TableAbstractModel.

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;
    }
}

}

Теперь я пытался создать очень простой макет, состоящий только из таблицы и соответствующих JTextfields и JButtons, чтобы проверить, действительно ли работает таблица.

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

}

}

Теперь проблема в том, что как только я пытаюсь запустить графический интерфейс, я просто получаю целую кучу ошибок.

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)

Я действительно застрял прямо сейчас и понятия не имею, как это исправить. Если бы кто-нибудь мог показать мне, что я делаю неправильно, это было бы здорово. С другой стороны, я должен использовать LinkedList в своей программе в разных классах. Как TableModel узнает, какой я хочу? Нужно ли мне что-то добавлять в TableModel, чтобы таблица автоматически обновлялась при добавлении или удалении учащегося?

Обновление:

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;

Работает ли этот метод для создания таблицы со связанным списком? Буду ли я тогда вызывать метод как

setStudentList(Studentlist); 

Если бы я инициализировал пустой LinkedList как таковой:

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

Спасибо за помощь.


person Nino    schedule 10.04.2013    source источник


Ответы (1)


LinkedList никогда не инициализируется...

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

Это означает, что при вызове getRowCount объектом data является null, следовательно, NullPointerException

Обновлено

У вас есть любое количество вариантов, которые вы можете использовать для передачи ссылки на main LinkedList в пользовательский интерфейс, но все зависит от того, как работает ваш рабочий процесс.

Ты мог...

Передайте ссылку на пользовательский интерфейс через его конструктор....

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

Ты мог...

Передайте LinkedList через метод в вашем классе GUI...

public class GUI extends JFrame {

    //...//

    public GUI(Database DB) {...}

    public void setStudent(LinkedList<Student> students) {
        StudentTable.setModel(new StudentTableModel(students));
    }
}

Обновлено с примером

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;
        }

    }

}
person MadProgrammer    schedule 10.04.2013
comment
Ой ну спасибо. Итак, как именно мне его инициализировать? На что бы я его поставил? Я правда не знаю на данный момент... - person Nino; 10.04.2013
comment
Ну, я думаю, LinkedList<Student> data = new LinkedList<Student>(); будет достаточно. - person MadProgrammer; 10.04.2013
comment
Забудь, я знаю, что ты имеешь в виду, просто немного устал ;D Спасибо! Можете ли вы сказать мне что-нибудь на другие мои вопросы? - person Nino; 10.04.2013
comment
Моя проблема в том, что я не вижу таблицу в графическом интерфейсе. - person Nino; 10.04.2013
comment
По сути, табличная модель будет использовать все, что вы LinkedList передадите ей при ее построении. Если вы хотите изменить его позже, я бы просто создал новый StudentTableModel, передав ему LinkedList, который вы хотите использовать, и установил его в качестве модели таблицы. - person MadProgrammer; 10.04.2013
comment
Хорошо. Так как у меня есть LinkedList‹Studentlist› и LinkedList‹Student› в моей программе, как мне сказать ей использовать LinkedList‹Studentlist›? Потому что они оба являются одним и тем же типом связанного списка. - person Nino; 10.04.2013
comment
Мне кажется, что Student и Studentlist не одного типа - person MadProgrammer; 10.04.2013
comment
извините, я имел в виду, что у меня есть два LinkedList‹Student›, которые называются «Студенты» и «Список студентов». - person Nino; 10.04.2013
comment
По сути, создайте новый StudentTableModel, передав все LinkedList, которые вы хотите использовать (например, StudentTable.setModel(new StudentTableModel(Studentlist));), и он будет обновляться автоматически. - person MadProgrammer; 10.04.2013
comment
хорошо, я пробовал это, и это дало мне ошибку? Я проверю это снова. - person Nino; 10.04.2013
comment
хорошо, сейчас нет ошибки, но поскольку я инициализирую список в классе графического интерфейса, разве он не отличается от списка в другом моем классе? А не могли бы вы мне сказать, почему мой стол практически невидим? Это просто маленькое серое пятнышко. - person Nino; 10.04.2013
comment
1- Да. Если вам нужно, вы можете передать LinkedList из другого класса как часть инициализации графического интерфейса, но это сводится к тому, как работает ваш рабочий процесс 2- Это из-за FlowLayout. По сути, ваша таблица не имеет размера, потому что в ней нет данных. Я бы использовал другой менеджер макетов (или составные макеты) - person MadProgrammer; 10.04.2013
comment
Хорошо спасибо. Как я могу это сделать? Да, я буду использовать другую раскладку, сейчас все это тестирую. - person Nino; 10.04.2013
comment
@Nino опубликуйте еще один вопрос о LayoutManager или погуглите (существуют сотни руководств). Комментарии не предназначены для дополнительных вопросов, а только для пояснений относительно исходного вопроса. - person Guillaume Polet; 10.04.2013
comment
Мой вопрос в том, как передать LinkedList из моего другого класса. И это связано с моим первоначальным вопросом о том, какой связанный список использовать в таблице. Я знаю, как работают другие макеты. - person Nino; 10.04.2013
comment
У вас есть дюжина вариантов передачи связанного списка, но все зависит от того, как работает ваш рабочий процесс. Вы можете передать его через параметр в конструкторе или передать его в качестве параметра какому-либо другому методу, который вы можете использовать для прямого доступа к связанному списку. - person MadProgrammer; 10.04.2013
comment
Спасибо, но мне это не очень помогает, так как я не знаком с этими опциями. Как мне передать его в конструкторе? - person Nino; 10.04.2013
comment
Точно так же, как вы передали ему базу данных - person MadProgrammer; 10.04.2013
comment
Будет ли это работать: общедоступный графический интерфейс (база данных БД, LinkedList‹Student›Studentlist)? - person Nino; 10.04.2013
comment
Еще раз спасибо, извините, что беспокою вас так долго, но у меня немного времени, так как это школьный проект. На данный момент я пытаюсь реализовать метод setStudent. Я понимаю, как это работает, но у меня вопрос, как мне это назвать? Я знаю, что вызываю setStudent(); а что мне поставить в скобки? Должен ли я инициализировать другой LinkedList в классе графического интерфейса и вызывать с ним метод? - person Nino; 10.04.2013
comment
Я бы инициализировал вашу табличную модель пустым LinkedList, как вы делаете сейчас. Используйте метод setStudent для передачи другого LinkedList, когда вы будете готовы, это заменит первый связанный список тем, который вы передаете методу set. - person MadProgrammer; 10.04.2013
comment
благодарю вас. Я понимаю, что вы пытаетесь сказать, но не совсем понимаю, как это будет работать. Я покажу вам, что я пробовал, может быть, это имеет смысл ;) Я укажу это в вопросе - person Nino; 10.04.2013