«Концептуально», идея довольно проста и подробно описана в Как использовать таблицы
Вам нужно начать с определения вашего редактора (и средства визуализации).Я решил обернуть оба вместе для простоты, так как большая часть функциональности повторяется для обоих.
public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private File source;
private JButton button;
public TableDeleteButtonEditor() {
button = new JButton();
button.addActionListener(new LoadActionListener());
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
protected JButton prepare(JTable table, Object value, boolean isSelected, int row, int column) {
if (!(value instanceof File)) {
source = null;
button.setEnabled(false);
return null;
}
source = (File) value;
button.setEnabled(true);
button.setText(source.getName());
button.setToolTipText(source.getPath());
return button;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return prepare(table, value, isSelected, row, column);
}
@Override
public Object getCellEditorValue() {
return source;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
return prepare(table, value, isSelected, row, column);
}
public class LoadActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent evt) {
// Here, you need to make some decisions about what to do...
// You have a reference to the File instance
System.out.println("You clicked " + source);
stopCellEditing();
}
}
}
Поскольку, вероятно, у вас будет только один активный редактор, когда когда-либо вызывается getTableCellEditorComponent
вам нужно получить ссылку на базовые данные (т.е. ссылку File
).
Как правило, редактор возвращает значение обратно в модель, в этом случае я не уверен, чтосмысл.Не говорю, что вы не можете этого сделать, но я бы поставил под сомнение цель.
Для моего примера мне нужна была только ссылка на сам File
, поэтому, технически, мне нужен был только один столбец,Вместо этого я разработал модель, в которой требовалось два столбца, но использовал ссылку File
для заполнения обоих.Это хороший пример, который демонстрирует способность «простого» объекта быть разложенным на несколько частей и представляться моделью по-другому ...
public class FileTableModel extends AbstractTableModel {
private List<File> files;
public FileTableModel(List<File> files) {
this.files = files;
}
@Override
public int getRowCount() {
return files.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 1;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 1: return File.class;
default: return String.class;
}
}
@Override
public Object getValueAt(int row, int col) {
File file = files.get(row);
switch (col) {
case 0: return file.getName();
case 1: return file;
}
return null;
}
}
Теперь важными частями здесь являютсяisCellEditable
и getColumnClass
методы.Они помогают определить, какие ячейки можно редактировать, и предоставляют точку входа для поиска средств визуализации / редакторов для JTable
, что подводит нас к следующему шагу: вам необходимо настроить JTable
для поддержки вашего пользовательского редактора / средства визуализации
Есть несколько способов сделать это, но для простоты setDefaultRenderer
и setDefaultEditor
должны работать очень хорошо ...
List<File> files = Arrays.asList(new File(".").listFiles());
FileTableModel model = new FileTableModel(files);
JTable table = new JTable(model);
table.setDefaultEditor(File.class, new TableDeleteButtonEditor());
table.setDefaultRenderer(File.class, new TableDeleteButtonEditor());
nb: Вы можете использоватьодин экземпляр TableDeleteButtonEditor
, мне просто лень с копией и вставкой
И оттуда вы теперь сможете представлять список File
с в JTable
где последний столбец является кнопкой (с именем файла) и при щелчке в этом примере будет напечатан File
reference
Runnable Example ...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.EventObject;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
List<File> files = Arrays.asList(new File(".").listFiles());
FileTableModel model = new FileTableModel(files);
JTable table = new JTable(model);
table.setDefaultEditor(File.class, new TableDeleteButtonEditor());
table.setDefaultRenderer(File.class, new TableDeleteButtonEditor());
add(new JScrollPane(table));
}
}
public class FileTableModel extends AbstractTableModel {
private List<File> files;
public FileTableModel(List<File> files) {
this.files = files;
}
@Override
public int getRowCount() {
return files.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 1;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 1:
return File.class;
default:
return String.class;
}
}
@Override
public Object getValueAt(int row, int col) {
File file = files.get(row);
switch (col) {
case 0:
return file.getName();
case 1:
return file;
}
return null;
}
}
public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
private File source;
private JButton button;
public TableDeleteButtonEditor() {
button = new JButton();
button.addActionListener(new LoadActionListener());
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
protected JButton prepare(JTable table, Object value, boolean isSelected, int row, int column) {
if (!(value instanceof File)) {
source = null;
button.setEnabled(false);
return null;
}
source = (File) value;
button.setEnabled(true);
button.setText(source.getName());
button.setToolTipText(source.getPath());
return button;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return prepare(table, value, isSelected, row, column);
}
@Override
public Object getCellEditorValue() {
return source;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
return prepare(table, value, isSelected, row, column);
}
public class LoadActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent evt) {
// Here, you need to make some decisions about what to do...
// You have a reference to the File instance
System.out.println("You clicked " + source);
stopCellEditing();
}
}
}
}