Java 从AbstractTableModel扩展时如何切换JTable中复选框的值

Java 从AbstractTableModel扩展时如何切换JTable中复选框的值,java,swing,jtable,defaulttablemodel,abstracttablemodel,Java,Swing,Jtable,Defaulttablemodel,Abstracttablemodel,我希望你能帮我解决一个困扰我好几天的问题 我在网上读了很多关于SO的答案和各种各样的例子,我尽最大努力阅读DefaultTableModel的源代码,试图了解幕后发生的事情,但不幸的是,我仍然完全没有更全面的了解。我似乎找不到任何例子、文章或视频来解释TableModel是如何或为什么这样做的,以及如何根据我的需要有效地修改它 我正在做一个项目,我需要在JTable中显示与每个对象关联的数据。我有一个ObjectCollection类,它保存ArrayList中文件夹中的所有对象。正是这个集合被

我希望你能帮我解决一个困扰我好几天的问题

我在网上读了很多关于SO的答案和各种各样的例子,我尽最大努力阅读DefaultTableModel的源代码,试图了解幕后发生的事情,但不幸的是,我仍然完全没有更全面的了解。我似乎找不到任何例子、文章或视频来解释TableModel是如何或为什么这样做的,以及如何根据我的需要有效地修改它

我正在做一个项目,我需要在JTable中显示与每个对象关联的数据。我有一个ObjectCollection类,它保存ArrayList中文件夹中的所有对象。正是这个集合被传递到我的自定义TableModel以填充JTable。然而,问题是我需要JTable有一个列(在本例中为列0),其中包含用户可以与之交互的复选框。但是,复选框的状态不会反映在对象或ObjectCollection中。有一个单独的方法,在用户做出任何选择后调用该方法,然后在JTable中搜索选中的行,并对ObjectCollection中的相应对象进行操作,因此对象本身和集合都不需要知道复选框的状态。从本质上讲,这就好像TableModel保存着来自两个不同来源的数据——该行中对象的第1列到第4列,以及该行第0列中单元格的选中状态。我希望这是有意义的,但如果不是,我下面的示例代码将比我的文字更好地演示它

我的问题有两方面。首先,虽然我可以显示复选框,并且可以注册对它们的单击,但我不知道如何实际切换复选框的选中状态(单击复选框时不会发生任何事情)。其次,假设我能弄清楚如何切换复选框状态,我不知道如何使用getValue()方法返回它,因为它不是对象的成员(如果我不清楚,请再次参阅下面的示例代码)

由于各种原因,我无法发布真实项目中的代码(目前),因此我为这个问题创建了一个假示例项目。原理是完全相同的,我面临的问题也是如此,所以如果我能在这个例子中解决它,我可以在我的真实代码库中以同样的方式解决它。无论如何,这是我到目前为止得到的示例代码

一个简单的示例对象

public class ExampleMovie {

    private final String title;
    private final String year;
    private final String director;
    private final double score;

    public ExampleMovie(String title, String year, String director, double score) {
        this.title = title;
        this.year = year;
        this.director = director;
        this.score = score;
    }

    public String getTitle() {
        return title;
    }

    public String getYear() {
        return year;
    }

    public String getDirector() {
        return director;
    }

    public double getScore() {
        return score;
    }
}
对象集合

public class ExampleMovieCollection {

    private List<ExampleMovie> allMovies;

    public ExampleMovieCollection() {
        allMovies = new ArrayList<>();
    }

    public void addMovie(ExampleMovie movie) {
        allMovies.add(movie);
    }

    public void removeMovie(ExampleMovie movie) {
        if (allMovies.contains(movie)) {
            allMovies.remove(movie);
        }
    }

    public List<ExampleMovie> getMovies() {
        return allMovies;
    }
}
除了无法设置或检索第0列中的复选框状态外,上述操作非常有效。当我点击带有System.out.println语句的复选框时,我可以确认正在调用setValueAt()方法,但我不知道如何实际切换选中状态,不幸的是,文档没有任何帮助,而且我找到的答案/教程都没有涉及此特定问题

希望我已经提供了足够的信息,但如果没有,请让我知道,我会相应地编辑问题

为清晰起见进行编辑:在示例代码中,向ExampleMovie类添加一个布尔值并将该值反映在表的第0列中是很简单的,但不幸的是,在我正在使用的实际代码库中,这不是一个选项,因此我想我的具体问题是:是否有一种方法可以在ExampleMovie类中没有相应的数据成员的情况下获取并设置/切换第0列中的复选框值?如果这是不可能的,或者实现起来非常简单,有人能告诉我一种显示数据的替代方法吗

第二次编辑:忽略我。实际上,我可以相对轻松地向正在使用的类添加新的数据成员。我认为吉尔伯特·勒布兰科的回答是正确的。我猜这一直是一个重复的问题。对不起!谢谢你的帮助,我真的很感激


谢谢。

您提供的代码已终止。我将主类的名称从ExampleForm更改为ExampleMovieGUI

Exception in thread "main" java.lang.NullPointerException
    at com.ggl.testing.ExampleMovieGUI.createExampleTable(ExampleMovieGUI.java:45)
    at com.ggl.testing.ExampleMovieGUI.<init>(ExampleMovieGUI.java:27)
    at com.ggl.testing.ExampleMovieGUI.createAndShowGui(ExampleMovieGUI.java:32)
    at com.ggl.testing.ExampleMovieGUI.main(ExampleMovieGUI.java:49)
线程“main”java.lang.NullPointerException中的异常 在com.ggl.testing.ExampleMovieGUI.createExampleTable上(ExampleMovieGUI.java:45) 在com.ggl.testing.ExampleMovieGUI上。(ExampleMovieGUI.java:27) 在com.ggl.testing.ExampleMovieGUI.createAndShowGui(ExampleMovieGUI.java:32) 位于com.ggl.testing.ExampleMovieGUI.main(ExampleMovieGUI.java:49) 在修复了所有异常终止之后,我向ExampleMovie类添加了一个布尔值。以下是GUI的外观

我把所有的类都放在内部类中,这样我就可以将完整的可运行代码作为一个块发布

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

public class ExampleMovieGUI {
    
    public static void main(String[] args) {
        ExampleMovieGUI gui = new ExampleMovieGUI();
        
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("TableModel Example");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                
                frame.add(gui.createExampleTable(), BorderLayout.CENTER);
                
                frame.pack();
                frame.setLocationRelativeTo(null); // Center on primary monitor
                frame.setVisible(true);
            }
        });
    }

    private JTable exampleTable;
    private JScrollPane tableScrollPane;
    private ExampleMovieCollection movieCollection;
    private ExampleMovieCollectionTableModel tableModel;

    public ExampleMovieGUI() {
        movieCollection = new ExampleMovieCollection();
        movieCollection.addMovie(new ExampleMovie(
                "The Shawshank Redemption", "1994", "Frank Darabont", 9.3));
        movieCollection.addMovie(new ExampleMovie(
                "The Godfather", "1972", "Francis Ford Coppola", 9.2));
        movieCollection.addMovie(new ExampleMovie(
                "The Godfather: Part II", "1974","Francis Ford Coppola", 9.1));
        movieCollection.addMovie(new ExampleMovie(
                "The Dark Knight", "2008", "Christopher Nolan", 9.0));
        movieCollection.addMovie(new ExampleMovie(
                "Schindler's List", "1993", "Steven Spielberg", 8.9));
    }

    private JPanel createExampleTable() {
        JPanel panel = new JPanel(new BorderLayout());
        
        tableModel = new ExampleMovieCollectionTableModel(movieCollection);
        exampleTable = new JTable(tableModel);
        exampleTable.setPreferredScrollableViewportSize(
                exampleTable.getPreferredSize());
        exampleTable.changeSelection(0, 0, false, false);
        exampleTable.setAutoCreateRowSorter(true);
        tableScrollPane = new JScrollPane(exampleTable);
       
        panel.add(tableScrollPane, BorderLayout.CENTER);
        
        return panel;
    }
    
    public class ExampleMovieCollectionTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;
        
        private List<ExampleMovie> items;
        private String[] columnNames = {"Checked?", "Title", "Year", 
                "IMDB Score", "Director"};

        public ExampleMovieCollectionTableModel(
                ExampleMovieCollection movieCollection) {
            this.items = new ArrayList<>(movieCollection.getMovies());
        }

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

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

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

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            // Only the first column in the table should be editable
            return columnIndex == 0;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            ExampleMovie item = items.get(rowIndex);
            switch (columnIndex) {
                case 0: return item.isSelected();
                case 1: return item.getTitle();
                case 2: return item.getYear();
                case 3: return item.getScore();
                case 4: return item.getDirector();
                default: return null;
            }
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            // How do I toggle the checked state of the cell when columnIndex == 0?
            System.out.println("(" + rowIndex + ", " + columnIndex + 
                    ") clicked. Value = " + aValue);
            if (columnIndex == 0) {
                ExampleMovie item = items.get(rowIndex);
                item.setSelected(Boolean.valueOf(aValue.toString()));
            }
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 0) {
                return Boolean.class;
            } else if (columnIndex == 3) {
                return Double.class;
            }
            return String.class;
        }
    }
    
    public class ExampleMovieCollection {

        private List<ExampleMovie> allMovies;

        public ExampleMovieCollection() {
            allMovies = new ArrayList<>();
        }

        public void addMovie(ExampleMovie movie) {
            allMovies.add(movie);
        }

        public void removeMovie(ExampleMovie movie) {
            if (allMovies.contains(movie)) {
                allMovies.remove(movie);
            }
        }

        public List<ExampleMovie> getMovies() {
            return allMovies;
        }
    }
    
    public class ExampleMovie {
        
        private boolean selected;

        private final String title;
        private final String year;
        private final String director;
        private final double score;

        public ExampleMovie(String title, String year, 
                String director, double score) {
            this.title = title;
            this.year = year;
            this.director = director;
            this.score = score;
            this.selected = false;
        }

        public String getTitle() {
            return title;
        }

        public String getYear() {
            return year;
        }

        public String getDirector() {
            return director;
        }

        public double getScore() {
            return score;
        }

        public boolean isSelected() {
            return selected;
        }

        public void setSelected(boolean selected) {
            this.selected = selected;
        }
        
    }
    
}
导入java.awt.BorderLayout;
导入java.util.ArrayList;
导入java.util.List;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.JTable;
导入javax.swing.SwingUtilities;
导入javax.swing.table.AbstractTableModel;
公共类示例MovieGUI{
公共静态void main(字符串[]args){
ExampleMovieGUI=新ExampleMovieGUI();
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
JFrame frame=新JFrame(“表格模型示例”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(gui.createExampleTable(),BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);//在主监视器上居中
frame.setVisible(true);
}
});
}
私有JTable示例;
私有JScrollPane表crollPane;
私有示例movieCollection movieCollection;
私有示例MovieCollectionTableModel tableModel;
公共示例电影
Exception in thread "main" java.lang.NullPointerException
    at com.ggl.testing.ExampleMovieGUI.createExampleTable(ExampleMovieGUI.java:45)
    at com.ggl.testing.ExampleMovieGUI.<init>(ExampleMovieGUI.java:27)
    at com.ggl.testing.ExampleMovieGUI.createAndShowGui(ExampleMovieGUI.java:32)
    at com.ggl.testing.ExampleMovieGUI.main(ExampleMovieGUI.java:49)
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

public class ExampleMovieGUI {
    
    public static void main(String[] args) {
        ExampleMovieGUI gui = new ExampleMovieGUI();
        
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("TableModel Example");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                
                frame.add(gui.createExampleTable(), BorderLayout.CENTER);
                
                frame.pack();
                frame.setLocationRelativeTo(null); // Center on primary monitor
                frame.setVisible(true);
            }
        });
    }

    private JTable exampleTable;
    private JScrollPane tableScrollPane;
    private ExampleMovieCollection movieCollection;
    private ExampleMovieCollectionTableModel tableModel;

    public ExampleMovieGUI() {
        movieCollection = new ExampleMovieCollection();
        movieCollection.addMovie(new ExampleMovie(
                "The Shawshank Redemption", "1994", "Frank Darabont", 9.3));
        movieCollection.addMovie(new ExampleMovie(
                "The Godfather", "1972", "Francis Ford Coppola", 9.2));
        movieCollection.addMovie(new ExampleMovie(
                "The Godfather: Part II", "1974","Francis Ford Coppola", 9.1));
        movieCollection.addMovie(new ExampleMovie(
                "The Dark Knight", "2008", "Christopher Nolan", 9.0));
        movieCollection.addMovie(new ExampleMovie(
                "Schindler's List", "1993", "Steven Spielberg", 8.9));
    }

    private JPanel createExampleTable() {
        JPanel panel = new JPanel(new BorderLayout());
        
        tableModel = new ExampleMovieCollectionTableModel(movieCollection);
        exampleTable = new JTable(tableModel);
        exampleTable.setPreferredScrollableViewportSize(
                exampleTable.getPreferredSize());
        exampleTable.changeSelection(0, 0, false, false);
        exampleTable.setAutoCreateRowSorter(true);
        tableScrollPane = new JScrollPane(exampleTable);
       
        panel.add(tableScrollPane, BorderLayout.CENTER);
        
        return panel;
    }
    
    public class ExampleMovieCollectionTableModel extends AbstractTableModel {

        private static final long serialVersionUID = 1L;
        
        private List<ExampleMovie> items;
        private String[] columnNames = {"Checked?", "Title", "Year", 
                "IMDB Score", "Director"};

        public ExampleMovieCollectionTableModel(
                ExampleMovieCollection movieCollection) {
            this.items = new ArrayList<>(movieCollection.getMovies());
        }

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

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

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

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            // Only the first column in the table should be editable
            return columnIndex == 0;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            ExampleMovie item = items.get(rowIndex);
            switch (columnIndex) {
                case 0: return item.isSelected();
                case 1: return item.getTitle();
                case 2: return item.getYear();
                case 3: return item.getScore();
                case 4: return item.getDirector();
                default: return null;
            }
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            // How do I toggle the checked state of the cell when columnIndex == 0?
            System.out.println("(" + rowIndex + ", " + columnIndex + 
                    ") clicked. Value = " + aValue);
            if (columnIndex == 0) {
                ExampleMovie item = items.get(rowIndex);
                item.setSelected(Boolean.valueOf(aValue.toString()));
            }
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 0) {
                return Boolean.class;
            } else if (columnIndex == 3) {
                return Double.class;
            }
            return String.class;
        }
    }
    
    public class ExampleMovieCollection {

        private List<ExampleMovie> allMovies;

        public ExampleMovieCollection() {
            allMovies = new ArrayList<>();
        }

        public void addMovie(ExampleMovie movie) {
            allMovies.add(movie);
        }

        public void removeMovie(ExampleMovie movie) {
            if (allMovies.contains(movie)) {
                allMovies.remove(movie);
            }
        }

        public List<ExampleMovie> getMovies() {
            return allMovies;
        }
    }
    
    public class ExampleMovie {
        
        private boolean selected;

        private final String title;
        private final String year;
        private final String director;
        private final double score;

        public ExampleMovie(String title, String year, 
                String director, double score) {
            this.title = title;
            this.year = year;
            this.director = director;
            this.score = score;
            this.selected = false;
        }

        public String getTitle() {
            return title;
        }

        public String getYear() {
            return year;
        }

        public String getDirector() {
            return director;
        }

        public double getScore() {
            return score;
        }

        public boolean isSelected() {
            return selected;
        }

        public void setSelected(boolean selected) {
            this.selected = selected;
        }
        
    }
    
}