1

I want to create a JTable cell consisting of a text field and a button, and here is where I am: I create a cell renderer like below,

public class ButtonTextFieldCellRenderer extends JPanel implements TableCellRenderer, ActionListener {

    private JTextField t;
    private JButton b;
    public ButtonTextFieldCellRenderer(){
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        t = new JTextField(50);
        t.setPreferredSize(new Dimension(50,16));
        add(t);

        b = new JButton("...");
        b.setPreferredSize(new Dimension(16,16));
        b.addActionListener(this);
        add(b);
        add(Box.createHorizontalGlue());
    }
    @Override
    public Component getTableCellRendererComponent(JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row,
            int column) {
        if (isSelected)
            setBackground( table.getSelectionBackground() );
        else
            setBackground( table.getBackground() );

        return this;
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        if(e.getSource() instanceof JButton){
            JOptionPane.showConfirmDialog(this, "you clicked a button", "Info", JOptionPane.CLOSED_OPTION);
        }
    }
}

It appear some kinds of what I wanted, a text field and an associated button as a table cell, but I have one issue: When I double click the field, the text field occupies the whole cell, and the button disappears.

I think I need to write a customized cell editor too but don't know how. Anyone care to shed a light on this?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
J.E.Y
  • 1,173
  • 2
  • 15
  • 37
  • `t.setPreferredSize(new Dimension(50,16));` 1) See [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/q/7229226/418556) (Yes.) 2) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete and Verifiable Example). – Andrew Thompson Jul 06 '14 at 02:05
  • You'll need a cell editor, too. – trashgod Jul 06 '14 at 03:35
  • For [example](http://stackoverflow.com/a/24369563/230513). – trashgod Jul 06 '14 at 04:12
  • thanks Andy and Trashgod. After some tests I figure that I need to use a extended AbstractCellEditor rather than a CellRenderer in my case. – J.E.Y Jul 07 '14 at 02:37

2 Answers2

0

After studying the sample code I came out with my own solution. It appears to me that I need to create a customized cell editor as opposed to a cell renderer. The runnable code below doesn't include the value persistence logic, but it suffices me visually:

public class ButtonTextFieldCellTest extends JPanel {

static class ButtonTextFieldCell extends AbstractCellEditor implements
        TableCellEditor, ActionListener {

    private JPanel panel;
    private JTextField t;
    JButton b;

    public ButtonTextFieldCell() {
        this("");
    }

    public ButtonTextFieldCell(String txt) {

        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        t = new JTextField(50);
        t.setText(txt);
        // t.setPreferredSize(new Dimension(50,16));
        panel.add(t);
        b = new JButton("...");
        b.setPreferredSize(new Dimension(16, 16));
        b.addActionListener(this);
        panel.add(b);
        panel.add(Box.createHorizontalGlue());
    }

    @Override
    public Object getCellEditorValue() {
        return this;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table,
            Object value, boolean isSelected, int row, int column) {
        return panel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() instanceof JButton) {
            JOptionPane.showConfirmDialog(panel, "you clicked a button",
                    "Info", JOptionPane.CLOSED_OPTION);
        }
    }

    @Override
    public String toString() {
        return t.getText();
    }
}

static class MyModel extends AbstractTableModel {

    String[] colName = new String[] { "index", "Test" };

    Object[][] data = new Object[][] { { "1", new ButtonTextFieldCell() },
            { "2", new ButtonTextFieldCell() },
            { "3", new ButtonTextFieldCell() },
            { "4", new ButtonTextFieldCell() } };

    @Override
    public Class<?> getColumnClass(int col) {
        return data[0][col].getClass();
    }

    @Override
    public String getColumnName(int col) {
        return colName[col];
    }

    @Override
    public boolean isCellEditable(int arg0, int arg1) {
        return true;
    }

    @Override
    public int getColumnCount() {
        return data[0].length;
    }

    @Override
    public int getRowCount() {
        return data.length;
    }

    @Override
    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

}

// create a table of two columns only
private JTable table;

public ButtonTextFieldCellTest() {
    table = new JTable(new MyModel());
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    table.setDefaultEditor(ButtonTextFieldCell.class,
            new ButtonTextFieldCell());
    TableColumnModel tcm = table.getColumnModel();
    for (int i = 0; i < tcm.getColumnCount(); i++) {
        TableColumn tc = tcm.getColumn(i);
        if (i == 1) {
            tc.setPreferredWidth(250);
        }
    }
    add(new JScrollPane(table), BorderLayout.CENTER);

}

private static void createAndShowUI() {
    JFrame frame = new JFrame("hello kitty");
    frame.getContentPane().add(new ButtonTextFieldCellTest());
    frame.setSize(new Dimension(400, 300));
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            createAndShowUI();
        }
    });
}

}

J.E.Y
  • 1,173
  • 2
  • 15
  • 37
0

You can add this code as part of creating your table's instance or an action such as a key released:

// First declare any component, say a JTextField
JTextField jt = new JTextField();

// The code below adds the component to the JTable column
this.jTable1.getColumnModel().getColumn(3).setCellEditor(new javax.swing.DefaultCellEditor(jt));
spongebob
  • 8,370
  • 15
  • 50
  • 83
Saleem
  • 1