# JButton in JTable ist nicht klickbar



## Curry (17. Feb 2011)

Moin Moin!

In einer JTable möchte ich in jeder Zeile zwei JButtons, je in einer eigenen Zelle, platzieren. Die Beiden Buttons werden auch richtig angezeigt, aber sie lassen sich weder optisch klicken noch wird "actionPerformed()" der Klasse "ButtonColumn" aufgerufen. Die Methode "getTableCellEditorComponent" der Klasse "ButtonColumn" wird beim Klicken auf einen der Buttons nicht aufgerufen.

In einer alten Version des Programm funktionieren die JButtons in der JTable der Klasse "ButtonColumn" super. In der neuen Version des Programms verwende ich ein eigenes, von AbstractTableModel abgeleitetes, TableModel.

Sieht jmd. das Problem und kann mir helfen?

Hier die GUI und inkl. der Klasse "ButtonColumn":

```
public class MainFrame extends JFrame implements ActionListener {
	
	 protected JLabel labelNum;
	 protected JTable table;
     protected JScrollPane scroller;
     protected MyTableModel tableModel;
	
	public MainFrame() {
		super("PaperList");

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		initComponents();
	}
	
	private void initComponents() {
		
		Container cp = getContentPane();
		cp.setLayout(new GridBagLayout());
		GridBagConstraints gbc = new GridBagConstraints();
		
		// Tabelle: Spalten
		DefaultTableColumnModel columnModel = new DefaultTableColumnModel();
		TableColumn col;
		
		col = new TableColumn(0, Configuration.getCellWidth("cell_width_title"));
		col.setHeaderValue("Title");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(1, Configuration.getCellWidth("cell_width_first_author"));
		col.setHeaderValue("Erstautor");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(2, Configuration.getCellWidth("cell_width_first_senior"));
		col.setHeaderValue("Seniorautor");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(3, Configuration.getCellWidth("cell_width_date"));
		col.setHeaderValue("Date");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(4, Configuration.getCellWidth("cell_width_journal"));
		col.setHeaderValue("Journal");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(5, Configuration.getCellWidth("cell_width_pdf"));
		col.setHeaderValue("");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		col = new TableColumn(6, Configuration.getCellWidth("cell_width_com"));
		col.setHeaderValue("");
		col.setResizable(false);
		columnModel.addColumn(col);
		
		// Tabelle: Inhalt
		tableModel = new MyTableModel();		
		
		// Tabelle: Darstellung
		table = new JTable(tableModel, columnModel);
		table.setPreferredScrollableViewportSize(new Dimension(columnModel.getTotalColumnWidth(), 300));
		
		// Tabelle: Buttons
		ButtonColumn buttonColumn1 = new ButtonColumn(this, table, tableModel, 5);
		ButtonColumn buttonColumn2 = new ButtonColumn(this, table, tableModel, 6);
		
		// Tabelle: Filter
		RowFilter<MyTableModel, Integer> ageFilter = new RowFilter<MyTableModel, Integer>() {
			public boolean include(Entry<? extends MyTableModel, ? extends Integer> entry) {
				MyTableModel tableModel = entry.getModel();
				Paper paper = tableModel.getPaper(entry.getIdentifier());
		
				if (paper.getFileName().startsWith("1")) {
						return true;
				}
				return false;
			}
		};
		
		RowFilter<MyTableModel, Integer> authorFilter = new RowFilter<MyTableModel, Integer>() {
			public boolean include(Entry<? extends MyTableModel, ? extends Integer> entry) {
				MyTableModel tableModel = entry.getModel();
				Paper paper = tableModel.getPaper(entry.getIdentifier());
		
				if (paper.getAuthorSenior().equals("Test")) {
						return true;
				}
				return false;
			}
		};
		
		TableRowSorter<MyTableModel> sorter = new TableRowSorter<MyTableModel>(tableModel);
//		sorter.setRowFilter(authorFilter); 
		table.setRowSorter(sorter);

		// Anzahl der angezeigten Paper in der Tabelle
		labelNum = new JLabel();
		labelNum.setText(getNumPaperString());
		gbc.gridy = 1;
		gbc.gridx = 1;
		cp.add(labelNum, gbc);
		
		// UPDATE-Button
		JButton button = new JButton("UPDATE");
		button.addActionListener(this);
		gbc.gridy = 3;
		gbc.gridx = 1;
		cp.add(button, gbc);
		
		// Tabelle einbinden
		gbc.gridy = 2;
		gbc.gridx = 1;
		cp.add(new JScrollPane(table), gbc);
		
		pack();
	}
	
	public String getNumPaperString() {
		return "Paper " + table.getRowCount() + " / " + tableModel.getRowCount();
	}
	
	public void actionPerformed(ActionEvent event) {
		System.out.println("actionPerformed --> UPDATE");
		tableModel.readDirectory("d:/test/");
		tableModel.fireTableDataChanged();
		labelNum.setText(getNumPaperString());
		System.out.println("Anzahl der Paper in der Tabelle = " + table.getRowCount());
	}
	
	class ButtonColumn extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener {
		
		JFrame frame;
		JTable table;
		MyTableModel tableModel;
		JButton renderButton;
		JButton editButton;
		String text;
		int column;
		
	    public ButtonColumn(JFrame frame, JTable table, MyTableModel tableModel, int column) {
	        super();
	        this.frame = frame;
	        this.table = table;
	        this.tableModel = tableModel;
	        this.column = column;
	        renderButton = new JButton();
	        
	        editButton = new JButton();
	        editButton.setFocusPainted( false );
	        editButton.addActionListener( this );
	
	        TableColumnModel columnModel = table.getColumnModel();
	        System.out.println("getColumnCount = " + columnModel.getColumnCount());
	        System.out.println("getWidth = " + columnModel.getColumn(this.column).getWidth());
	        columnModel.getColumn(this.column).setCellRenderer( this );
	        columnModel.getColumn(this.column).setCellEditor( this );
	    }
	
	    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
	    	System.out.println("(" + row + " / " + column + ")" + isSelected + " -> " + hasFocus + " -> " + value.toString());
	    	if (hasFocus) {
	        	renderButton.setForeground(table.getForeground());
	        	renderButton.setBackground(UIManager.getColor("Button.background"));
	        }
	        else if (isSelected) {
	        	renderButton.setForeground(table.getSelectionForeground());
	        	renderButton.setBackground(table.getSelectionBackground());
	        }
	        else {
	        	renderButton.setForeground(table.getForeground());
	        	renderButton.setBackground(UIManager.getColor("Button.background"));
	        }
	
	        renderButton.setText( (value == null) ? "" : value.toString() );
	        return renderButton;
	    }
	
	    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
	    	System.out.println("getTableCellEditorComponent");
	    	text = (value == null) ? "" : value.toString();
	        editButton.setText( text );
	        return editButton;
	    }
	
	    public Object getCellEditorValue() {
	    	System.out.println("getCellEditorValue");
	        return text;
	    }
	
	    public void actionPerformed(ActionEvent e) {
	    	System.out.println("actionPerformed --> BUTTON");
	    	int pmid = Integer.parseInt(table.getValueAt(table.getSelectedRow(), 0).toString());
			if(column == 5) {
				try {
					// Öffnen der PDF-Datei
					Desktop.getDesktop().open( new File(Configuration.getPaperPath() + pmid + ".pdf"));
				}
				catch(IOException ex) {
					ex.printStackTrace();
				}
			}
			else if(column == 6) {
				CommentDialog dialog = new CommentDialog(frame, tableModel, pmid);
				dialog.setVisible(true);
			}
	    }
	}

}
```

Und hier mein TableModel:

```
public class MyTableModel extends AbstractTableModel {
	
	 public static final int INDEX_TITLE 			= 0;
     public static final int INDEX_AUTHOR_FIRST		= 1;
     public static final int INDEX_AUTHOR_SENIOR	= 2;
     public static final int INDEX_DATE				= 3;
     public static final int INDEX_JOURNAL			= 4;
     public static final int INDEX_PDF				= 5;
     public static final int INDEX_COMMENT			= 6;
     
     private Vector<Paper> data;
     protected String[] columnNames;

	
	public MyTableModel() {
        data = new Vector<Paper>();
        readDatabase();
    }

	
	public int getColumnCount() {
		return 7;
	}
	
	public int getRowCount() {
		return data.size();
	}
	
	public Paper getPaper(int rowIndex) {
		return data.get(rowIndex);
	}
	
	public Object getValueAt(int rowIndex, int columnIndex) {		
		Paper paper = (Paper)data.get(rowIndex);
		switch (columnIndex) {
			case INDEX_TITLE:
				return paper.getTitle();
			case INDEX_AUTHOR_FIRST:
				return paper.getAuthorFirst();
			case INDEX_AUTHOR_SENIOR:
				return paper.getAuthorSenior();
			case INDEX_DATE:
				return paper.getDate();
			case INDEX_JOURNAL:
				return paper.getJournalISO();
			case INDEX_PDF:
				return "PDF";
			case INDEX_COMMENT:
				return "COM";
			default:
				return new Object();
		}
	}
	
	public void readDatabase() {
		DatabaseManager dm = new DatabaseManager();
		data = dm.read();
	}
	
	public void readDirectory(String path) {
		
		Vector<Paper> dataDel = new Vector<Paper>(data);	// Paper die nicht mehr in dem Verzeichnis vorhanden sind
		Vector<Paper> dataNew = new Vector<Paper>();		// Paper die neu in dem Verzeichnis sind
		
		File dir = new File(path);
		File[] files = dir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				if (files[i].isFile()) {
					int id = Integer.parseInt(files[i].getName().substring(0, files[i].getName().indexOf('.')));
					Paper paper = new Paper(id, files[i]);
					
					if(dataDel.contains(paper)) {
						dataDel.remove(paper);
					}
					else {
						data.add(paper);
						dataNew.add(paper);
						paper.eFetch();
						paper.addToDatabase();
					}
				}
			}
			
			for (Enumeration<Paper> e = dataDel.elements(); e.hasMoreElements(); ) {
				Paper paper = (Paper) e.nextElement();
				if(data.contains(paper)) {
					data.remove(paper);
					paper.removeFromDatabase();
				}
			}
		}
		
		String msg = 
			"DELETE	= " + dataDel.size() + "\r\n" +
			"NEW 	= " + dataNew.size() + "\r\n" + 
			"DATA 	= " + data.size() + "\r\n";
		JOptionPane.showMessageDialog(null, msg, "Error", JOptionPane.ERROR_MESSAGE);
	}	
}
```


----------



## Hogli (17. Feb 2011)

Hallo,
ich nutze zwar keine Buttons in einer Tabelle aber im Falle von editierbaren Feldern muss 
unten stehende Methode überschrieben werden. Im Falle der Buttonspalten dann eben true zurück
geben sonst false.


```
public boolean isCellEditable(int rowIndex, int columnIndex);
```

Eventuell hilft das schon

Hogli


----------



## KrokoDiehl (17. Feb 2011)

Das Problem ist, dass die Buttons in der Tabelle nur gemalt sind. Um sie klickbar zu machen, muss man wohl die Klicks in der Tabelle prüfen und wenn es eine entsprechende Zelle betrifft, einen eigenen Aufruf von 
	
	
	
	





```
actionPerformed()
```
 durchführen.
Damit der Button auch geklickt aussieht, muss man wohl auch noch händisch entsprechende Methoden ausführen ... das weiß ich aber nicht genauer. Ich denke es geht in Richtung 
	
	
	
	





```
button.getModel().setArmed(true);
```
Zu den Stichworten "JButton in JTable" lässt sich aber doch bestimmt einiges ergooglen.


----------



## André Uhres (17. Feb 2011)

Hallo Curry,

hier ist ein Beispiel wie du es machen könntest:


```
/*
 * TableLayoutDemo.java
 * benutzt die Klasse TableLayout.java,
 * hier findest du sie:
[url=http://wiki.byte-welt.net/wiki/TableLayout]TableLayout - Byte-Welt Wiki[/url]
(die Methoden addColumns, addRow, removeRow kannst du daraus entfernen)
 */
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Date;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.*;
public class TableLayoutDemo extends JFrame {
    private TableLayout table;
    public TableLayoutDemo() {
        super("TableLayout Demo");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 600);
        setLocationRelativeTo(null);
        //create empty TableLayout:
        table = new TableLayout();
        //
        table.setModel(new MyTableModel());
        TableColumnModel columnModel = table.getColumnModel();
        TableColumn col = columnModel.getColumn(0);
        col.setPreferredWidth(200);
        col.setHeaderValue("Title");
        getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
    }
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TableLayoutDemo().setVisible(true);
            }
        });

    }
}
class ActionPdf extends AbstractAction {
    public ActionPdf(final String name) {
        super(name);
    }
    @Override
    public void actionPerformed(final ActionEvent e) {
        final JTable table = (JTable) SwingUtilities.getAncestorOfClass(
                JTable.class, (Component) e.getSource());
        SwingUtilities.invokeLater(new DoActionPdf(table));
    }
    private static class DoActionPdf implements Runnable {
        private final JTable table;
        public DoActionPdf(final JTable table) {
            this.table = table;
        }
        @Override
        public void run() {
            int selectedRow = table.getSelectedRow();
            TableModel model = table.getModel();
            int row = table.convertRowIndexToModel(selectedRow);
            Object value = model.getValueAt(row, 0);
            System.out.println("PDF, selectedRow = " + selectedRow
                    + ", value = " + value);
        }
    }
}
class ActionComment extends AbstractAction {
    public ActionComment(final String name) {
        super(name);
    }
    @Override
    public void actionPerformed(final ActionEvent e) {
        final JTable table = (JTable) SwingUtilities.getAncestorOfClass(
                JTable.class, (Component) e.getSource());
        SwingUtilities.invokeLater(new DoActionComment(table));
    }
    private static class DoActionComment implements Runnable {
        private final JTable table;
        public DoActionComment(final JTable table) {
            this.table = table;
        }
        @Override
        public void run() {
            int selectedRow = table.getSelectedRow();
            TableModel model = table.getModel();
            int row = table.convertRowIndexToModel(selectedRow);
            Object value = model.getValueAt(row, 0);
            System.out.println("Comment, selectedRow = " + selectedRow
                    + ", value = " + value);
        }
    }
}
final class MyTableModel extends AbstractTableModel {
    public static final int INDEX_TITLE = 0;
    public static final int INDEX_AUTHOR_FIRST = 1;
    public static final int INDEX_AUTHOR_SENIOR = 2;
    public static final int INDEX_DATE = 3;
    public static final int INDEX_JOURNAL = 4;
    public static final int INDEX_PDF = 5;
    public static final int INDEX_COMMENT = 6;
    private Vector<Paper> data;
    protected String[] columnNames;
    public MyTableModel() {
        data = new Vector<Paper>();
        readDatabase();
    }
    @Override
    public int getColumnCount() {
        return 7;
    }
    @Override
    public int getRowCount() {
        return data.size();
    }
    public Paper getPaper(final int rowIndex) {
        return data.get(rowIndex);
    }
    @Override
    public Object getValueAt(final int rowIndex, final int columnIndex) {
        Paper paper = (Paper) data.get(rowIndex);
        switch (columnIndex) {
            case INDEX_TITLE:
                return paper.getTitle();
            case INDEX_AUTHOR_FIRST:
                return paper.getAuthorFirst();
            case INDEX_AUTHOR_SENIOR:
                return paper.getAuthorSenior();
            case INDEX_DATE:
                return paper.getDate();
            case INDEX_JOURNAL:
                return paper.getJournalISO();
            case INDEX_PDF:
                return paper.getPdf();
            case INDEX_COMMENT:
                return paper.getComment();
            default:
                return new Object();
        }
    }
    @Override
    public boolean isCellEditable(final int rowIndex, final int columnIndex) {
        return columnIndex == INDEX_PDF || columnIndex == INDEX_COMMENT;
    }
    public void readDatabase() {
//        DatabaseManager dm = new DatabaseManager();
//        data = dm.read();
        createTestData();
    }
    private void createTestData() {
        for (int row = 0; row < 4; row++) {
            JButton btPdf = new JButton();
            btPdf.setAction(new ActionPdf("PDF"));
            JButton btCom = new JButton();
            btCom.setAction(new ActionComment("COM"));
            data.add(new Paper(row, btPdf, btCom));//Test
        }
    }

}
class Paper {
    private final int id;
    private final File file;
    private final JButton pdf;
    private final JButton commment;
    Paper(final int id, final File file, final JButton pdf, final JButton comment) {
        this.id = id;
        this.file = file;
        this.pdf = pdf;
        this.commment = comment;
    }
    Paper(final int id, final JButton pdf, final JButton comment) {
        this(id, new File(""), pdf, comment);
    }
    Paper(final int id, final File file) {
        this(id, file, null, null);
    }
    public String getTitle() {
        return "getTitle" + id;
    }
    public String getAuthorFirst() {
        return "getAuthorFirst" + id;
    }
    public String getAuthorSenior() {
        return "getAuthorSenior" + id;
    }
    public Date getDate() {
        return new Date();
    }
    public String getJournalISO() {
        return "getJournalISO" + id;
    }
    public JButton getPdf() {
        return pdf;
    }
    public JButton getComment() {
        return commment;
    }
    public void eFetch() {
    }
    public void addToDatabase() {
    }
    public void removeFromDatabase() {
    }
}
```

Gruß,
André


----------



## Curry (17. Feb 2011)

Vielen Dank euch allen, besonderen Dank aber an André Uhres! Total toll wie du dir Mühe mit dem Beispiel gegeben hast. Und es funktioniert wunderbar. Ich muss mir das aber erstmal genauer anschauen um zu verstehen wie es funktioniert und zu sehen wo ggf. Vorteile gegenüber meiner Lösung sind.

Wenn ich die Klasse "isCellEditable()" wie nachfolgend gezeigt überschreibe, dann funktioniert es bereits.

```
@Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
     return columnIndex == INDEX_PDF || columnIndex == INDEX_COMMENT;
}
```

Ich habe jetzt auch gesehen, dass in der Dokumentation zur Methode "isCellEditable()" in der Klasse "AbstractTableModel" steht:
"Returns false. This is the default implementation for all cells.". Dann ist auch klar weshalb es bei mir nicht funktioniert hat! ;-)


----------

