I created a table for immediate interaction (for a Sudoku solver), but the mouse events (enter, exit, click) reach the cell renderer only after I click into the cell. (For each cell, I have to click once before the renderer is activated. Coming back to that cell later, it will work right away.)
How can I change my code to immediately activate the table cell? Or can I find out what exactly happens with the first mouse click, so I can perform these operations right after the table creation? (I have tried to catch the mouse events on all levels of the UI hierarchy, but could not find it.)
I have reduced the table to a 1×1 minimum and removed all unnecessary code. The remaining code is displayed below. Note that mouse over (a small black square is displayed) is active only after one click. (The code is complete and can be compiled as is.)
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventObject;
public class GUI extends JFrame
{
private class Table extends JTable
{
public Table()
{
super(new AbstractTableModel()
{
public int getRowCount() { return 1; }
public int getColumnCount() { return 1; }
public Object getValueAt(int x, int y) { return null; }
@Override public boolean isCellEditable(int x, int y) { return true; }
});
}
@Override public TableCellRenderer getCellRenderer(int x, int y) { return new Editor(); }
@Override public TableCellEditor getCellEditor(int x, int y) { return new Editor(); }
}
private class Editor extends JComponent implements TableCellEditor, TableCellRenderer, MouseListener
{
private boolean hasFocus = false;
public Editor()
{
addMouseListener(this);
}
@Override public void paintComponent(Graphics g)
{
if (hasFocus)
{
g.fillRect(0, 0, 9, 9);
}
}
public void mouseEntered(MouseEvent e)
{
hasFocus = true;
repaint();
}
public void mouseExited(MouseEvent e)
{
hasFocus = false;
repaint();
}
public void mouseClicked(MouseEvent e) { }
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public Object getCellEditorValue() { return 0; }
public boolean isCellEditable(EventObject e) { return true; }
public boolean shouldSelectCell(EventObject e) { return false; }
public boolean stopCellEditing() { return true; }
public void cancelCellEditing() { }
public void addCellEditorListener(CellEditorListener l) { }
public void removeCellEditorListener(CellEditorListener l) { }
public Component getTableCellEditorComponent(JTable t, Object v, boolean s, int x, int y) { return this; }
public Component getTableCellRendererComponent(JTable t, Object v, boolean s, boolean f, int x, int y) { return this; }
}
public static void main(String[] args)
{
new GUI();
}
public GUI()
{
setContentPane(new Table());
setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
}
That’s because a renderer is not supposed to handle events. A renderer is a unique component that is just used to paint every cell in a table or column.
When the table paints itself, it iterates through the cells. For each cell, the renderer component is modified, then a “screenshot” of the renderer component is taken and pasted into the table cell. So it can’t handle events. You should add an event listener on the table itself. Not on the renderer.
After a click, it works because your renderer is also an editor, and an editor can handle events. But it seems to me that your table is in fact not editable, and that you shouldn’t have an editor at all. Rather, add a listener on the table.