我正在尝试在JTable的列标题中添加一个select all框。我一直在使用此问题中提供的答案作为指导:How can I put a control in the JTableHeader of a JTable?。当我尝试运行它时,我不断收到错误消息。你能看到这个问题吗?我已经确认所有课程都在运作。我认为这与该行有关:
table.getColumnModel().getColumn(0).setHeaderRenderer(new SelectAllHeader(table, 0));
但是,我真的很新,所以我很难看到我做错了什么。
package guit2;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
public class Guit2 extends JFrame{
//CONSTRUCTOR - for the form
public Guit2()
{
DefaultTableModel model = new DefaultTableModel()
{
@Override
public Class<?> getColumnClass(int column)
{
switch(column)
{
case 0:
return Boolean.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
case 4:
return String.class;
default:
return String.class;
}
}
};
final JTable table = new JTable();
//The Form
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(200,200,800,300);
setTitle("Programming 1");
getContentPane().setLayout(null);
//ADD SCROLLPANE
JScrollPane scroll=new JScrollPane();
scroll.setBounds(70,80,600,100);
getContentPane().add(scroll);
//The Table
scroll.setViewportView(table);
//Assign the model to table
table.setModel(model);
model.addColumn("Select");
model.addColumn("Position");
model.addColumn("Team");
model.addColumn("Points");
model.addColumn("Manager");
//Set custom renderer to teams column
table.getColumnModel().getColumn(1).setCellRenderer(new ButtonRenderer());;
table.getColumnModel().getColumn(1).setCellEditor(new ButtonEditor(new JTextField()));
table.getColumnModel().getColumn(0).setHeaderRenderer(new SelectAllHeader(table, 0));
for(int i=0; i<=5;i++)
{
model.addRow(new Object[0]);
model.setValueAt(false,i,0);
model.setValueAt("Our Row" +(i+1), i, 1);
model.setValueAt("Our Column 2", i, 2);
model.setValueAt("Our Column 3", i, 3);
model.setValueAt("Our Column 4", i, 4);
}
//Obtain selected row
JButton btn = new JButton("Get Selected");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
//Get selected row
for(int i=0; i<table.getRowCount(); i++)
{
Boolean checked = Boolean.valueOf(table.getValueAt(i,0).toString());
String col = table.getValueAt(i, 1).toString();
//Display
if(checked)
{
JOptionPane.showMessageDialog(null, col);
}
}
}
});
//ADD Button to form
btn.setBounds(20,20,130,30);
getContentPane().add(btn);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
//INITIALISE JFRAME FROM
Guit2 form = new Guit2();
form.setVisible(true);;
}
});
}
}
//Button renderer class
class ButtonRenderer extends JButton implements TableCellRenderer
{
//Constructir
public ButtonRenderer(){
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object obj,
boolean selected, boolean focused, int row, int col) {
setText((obj==null) ? "":obj.toString());
return this;
}
}
//Button editor class
class ButtonEditor extends DefaultCellEditor
{
protected JButton btn;
private String lbl;
private Boolean clicked;
public ButtonEditor(JTextField txt){
super(txt);
btn=new JButton();
btn.setOpaque(true);
setClickCountToStart(1);
//When button is clicked
btn.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
fireEditingStopped();
}
});
}
//Overide a couple of methods
public Component getTableCellEditorComponent(JTable table, Object obj,
boolean selected, int row, int col) {
//Set button text
lbl=(obj==null) ? "":obj.toString();
btn.setText(lbl);
clicked=true;
return btn;
}
//If button cell value changes (clicked)
@Override
public Object getCellEditorValue(){
if(clicked)
{
JOptionPane.showMessageDialog(btn, lbl+" Clicked");
}
clicked = false;
return new String(lbl);
}
@Override
public boolean stopCellEditing(){
clicked=false;
return super.stopCellEditing();
}
@Override
protected void fireEditingStopped(){
super.fireEditingStopped();
}
}
/**
* A TableCellRenderer that selects all or none of a Boolean column.
*
* @param targetColumn the Boolean column to manage
* @see https://stackoverflow.com/a/7137801/230513
*/
class SelectAllHeader extends JToggleButton implements TableCellRenderer {
private static final String ALL = "✓ Select all";
private static final String NONE = "✓ Select none";
private JTable table;
private TableModel tableModel;
private JTableHeader header;
private TableColumnModel tcm;
private int targetColumn;
private int viewColumn;
public SelectAllHeader(JTable table, int targetColumn) {
super(ALL);
this.table = table;
this.tableModel = table.getModel();
if (tableModel.getColumnClass(targetColumn) != Boolean.class) {
throw new IllegalArgumentException("Boolean column required.");
}
this.targetColumn = targetColumn;
this.header = table.getTableHeader();
this.tcm = table.getColumnModel();
this.applyUI();
this.addItemListener(new ItemHandler());
header.addMouseListener(new MouseHandler());
tableModel.addTableModelListener(new ModelHandler());
}
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
return this;
}
private class ItemHandler implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
boolean state = e.getStateChange() == ItemEvent.SELECTED;
setText((state) ? NONE : ALL);
for (int r = 0; r < table.getRowCount(); r++) {
table.setValueAt(state, r, viewColumn);
}
}
}
@Override
public void updateUI() {
super.updateUI();
applyUI();
}
private void applyUI() {
this.setFont(UIManager.getFont("TableHeader.font"));
this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
this.setBackground(UIManager.getColor("TableHeader.background"));
this.setForeground(UIManager.getColor("TableHeader.foreground"));
}
private class MouseHandler extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
viewColumn = header.columnAtPoint(e.getPoint());
int modelColumn = tcm.getColumn(viewColumn).getModelIndex();
if (modelColumn == targetColumn) {
doClick();
}
}
}
private class ModelHandler implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
if (needsToggle()) {
doClick();
header.repaint();
}
}
}
// Return true if this toggle needs to match the model.
private boolean needsToggle() {
boolean allTrue = true;
boolean allFalse = true;
for (int r = 0; r < tableModel.getRowCount(); r++) {
boolean b = (Boolean) tableModel.getValueAt(r, targetColumn);
allTrue &= b;
allFalse &= !b;
}
return allTrue && !isSelected() || allFalse && isSelected();
}
}
错误消息显示为:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at guit2.SelectAllHeader.needsToggle(Guit2.java:316)
at guit2.SelectAllHeader.access$800(Guit2.java:229)
at guit2.SelectAllHeader$ModelHandler.tableChanged(Guit2.java:304)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(AbstractTableModel.java:231)
at javax.swing.table.DefaultTableModel.insertRow(DefaultTableModel.java:376)
at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:350)
at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:361)
at guit2.Guit2.<init>(Guit2.java:93)
at guit2.Guit2$3.run(Guit2.java:138)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
BUILD SUCCESSFUL (total time: 5 seconds)