我希望你能帮我解决一个困扰我好几天的问题!
我已经从网上阅读了很多答案和各种各样的例子,我已经尽力阅读defaulttablemodel的源代码,试图理解幕后发生的事情,但不幸的是,我仍然完全缺乏全局性。我似乎找不到任何例子、文章或视频来解释tablemodel如何或为什么做它所做的事情,以及如何根据我的需要有效地修改它。
我正在处理一个项目,需要在jtable中显示与每个对象相关联的数据。我有一个objectcollection类,它保存arraylist中文件夹中的所有对象。正是这个集合传递给我的自定义tablemodel来填充jtable。但是问题是,我需要jtable有一个列(在本例中是0列),其中包含用户可以与之交互的复选框。但是,复选框的状态不会反映在对象或objectcollection中。有一个单独的方法,在用户做出任何选择后调用该方法,然后在jtable中搜索选中的行并对objectcollection中的相应对象进行操作—因此对象本身和集合都不需要知道复选框的状态。基本上就好像tablemodel保存着来自两个不同来源的数据—该行中对象的第1列到第4列以及该行第0列中单元格的选中状态。我希望这是有意义的,但如果不是希望我下面的示例代码将演示它比我的话可以更好。
我遇到的问题是双重的。首先,虽然我可以让复选框显示,我可以注册点击他们,我不知道如何实际切换复选框的选中状态(什么都不会发生,当我点击复选框)。其次,假设我能弄清楚如何切换checkbox状态,我不知道如何使用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;
}
}
自定义表格模型
public class ExampleMovieCollectionTableModel extends AbstractTableModel {
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) {
return columnIndex == 0; // Only the first column in the table should be editable
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
ExampleMovie item = items.get(rowIndex);
switch (columnIndex) {
case 0: // How do I return the checked state of the cell as it isn't a member of item?
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);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return Boolean.class;
}
return String.class;
}
}
main()方法和gui创建代码等。
public class ExampleForm extends JFrame {
private JPanel rootPanel;
private JTable exampleTable;
private JScrollPane tableScrollPane;
private ExampleMovieCollection movieCollection;
private ExampleMovieCollectionTableModel tableModel;
public ExampleForm() {
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));
createExampleTable();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("TableModel Example");
frame.setContentPane(new ExampleForm().rootPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null); // Center on primary monitor
frame.setVisible(true);
}
private void createExampleTable() {
tableModel = new ExampleMovieCollectionTableModel(movieCollection);
exampleTable = new JTable(tableModel);
exampleTable.setPreferredScrollableViewportSize(exampleTable.getPreferredSize());
exampleTable.changeSelection(0, 0, false, false);
exampleTable.setAutoCreateRowSorter(true);
tableScrollPane.setViewportView(exampleTable);
}
public static void main(String[] args) {
createAndShowGui();
}
}
除了无法设置或检索第0列中的复选框状态外,上述操作非常有效。当我用system.out.println语句单击复选框时,我可以确认setvalueat()方法正在被调用,但我不知道如何实际切换选中状态,不幸的是,文档没有任何帮助,我找到的答案/教程都没有涉及这个特定问题。
希望我已经提供了足够的信息,但如果没有请让我知道,我会编辑的问题accorringly。
为清晰起见进行编辑:在示例代码中,向examplemovie类中添加一个布尔值并将该值反映在表的第0列中是很简单的,但不幸的是,在我正在使用的实际代码库中,这不是一个选项,所以我想我的具体问题是:有没有一种方法可以在examplemovie类中没有相应的数据成员的情况下获取和设置/切换第0列中的checkbox值?如果这是不可能的,或是难以置信的不平凡的实现,有人能告诉我一个替代方法显示数据,可能会做的把戏?
第二次编辑:忽略我。实际上,我可以相对容易地将一个新的数据成员添加到我正在使用的类中。我对吉尔伯特-勒布朗的回答是正确的。我想这一直是个重复的问题。很抱歉!谢谢你的帮助,我真的很感激。
谢谢。
1条答案
按热度按时间lzfw57am1#
您提供的代码异常终止。我将主类的名称从exampleform更改为examplemoviegui。
在修复了所有异常结束之后,我向examplemovie类添加了一个布尔值。下面是gui的外观。
我把所有的类都放在类内部,这样我就可以把完整的可运行代码作为一个块发布。