Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / April 2007

Tip: Looking for answers? Try searching our database.

Adding custom cell renderer to JTable causes delete problems

Thread view: 
Lionel van den Berg - 27 Apr 2007 10:36 GMT
I asked a question about this a while ago, but I was ill-prepared.
Rather than explaining I will hope that someone doesn't mind compiling
some code that I've included below. I stuck it all in a file called
JTableTest.java, compiled and ran it in Netbeans.

To see the problem, click Add a couple of times, and then select, last
row and press delete. Click on one of the other cells, see the result.

Can anyone tell me what the problem is? If I remove the row
tc.setCellEditor(new JTextFieldTableCellEditor()); it doesn't throw the
exception.

Thanks

Lionel

/*
 * JTableTest.java
 *
 * Created on 27 April 2007, 18:20
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package tciworks;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

/**
 *
 * @author Lionel van den Berg.
 */
public class JTableTest extends JFrame {

    public JTableTest() {
        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(0, 1));
        final TestTable table = new TestTable(new TestTableModel());
        contentPane.add(table);
        this.setContentPane(contentPane);
        this.setSize(new Dimension(400, 400));
        JButton addButton = new JButton("Add");
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ((TestTableModel)table.getModel()).addRow();
            }
        });
        JButton deleteButton = new JButton("Delete");
        deleteButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int rowNumber = table.getSelectedRow();
                ((TestTableModel)table.getModel()).deleteRow(rowNumber);
            }
        });
        contentPane.add(addButton);
        contentPane.add(deleteButton);
    }

    protected void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        if(e.getID() == WindowEvent.WINDOW_CLOSING) {
            System.exit(0);

        }
    }

    public static void main(String []args) {
        JTableTest test = new JTableTest();
        test.setVisible(true);
    }
}

/**
 * The constructer is extended to set the rendering, cell sizes, text
position
 * and so on.
 *
 * @author Lionel van den Berg
 */
class TestTable extends JTable {

    public TestTable(AbstractTableModel tableModel) {
        super(tableModel);
        setRendering();
    }

    /**
     * Sets the location of text in cells, fonts etc.
     *
     */
    private void setRendering() {
        AbstractTableModel tableModel = (AbstractTableModel)getModel();
        TableColumn tc;
        DefaultTableCellRenderer crEditible = new
DefaultTableCellRenderer(),
                crNotEditible = new DefaultTableCellRenderer();
        crEditible.setHorizontalAlignment(DefaultTableCellRenderer.CENTER);

crNotEditible.setHorizontalAlignment(DefaultTableCellRenderer.CENTER);
        crNotEditible.setBackground(new Color(230, 230, 230));

        //all columns should have centralised text
        for(int columnIndex = 0; columnIndex <
tableModel.getColumnCount();
            columnIndex++) {
            tc = getColumnModel().getColumn(columnIndex);
            tc.setCellEditor(new JTextFieldTableCellEditor());
            //if the column is editble, OR the whole table is not editible
            //(tableModel.isEditable() (means we don't distinguish between
            //cells). We use 0 for the row it's just a dummy row
because we
            //know it applies to the whole column
            if(tableModel.isCellEditable(0, columnIndex)) {
                tc.setCellRenderer(crEditible);
            } else {
                tc.setCellRenderer(crNotEditible);
            }
        }
        setHeaderBold();
    }

    /** Gets the number of columns in the table. */
    public int getNumColumns() {
        return getModel().getColumnCount();
    }

    /**
     * Sets the headings of the table columns bold making them more visble.
     */
    public void setHeaderBold() {
        //set the headers bold
        JTableHeader header = getTableHeader();
        if(header == null) {
            return;
        }
        final Font boldFont = header.getFont().deriveFont(Font.BOLD);
        final TableCellRenderer headerRenderer =
header.getDefaultRenderer();
        header.setDefaultRenderer(new TableCellRenderer() {
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
int row,
                    int column ) {
                Component comp =
headerRenderer.getTableCellRendererComponent(
                        table, value, isSelected, hasFocus, row, column);
                comp.setFont(boldFont);
                return comp;
            }
        });
    }
}

class TestTableModel extends AbstractTableModel {

    private String[] columnNames = {"Column 1", "Column 2", "Column 3"};
    private ArrayList list = new ArrayList();
    private int count = 0;

    public TestTableModel() {
    }

    public int getRowCount() {
        return list.size();
    }

    public int getColumnCount() {
        return getColumnNames().length;
    }

    public String getColumnName(int column) {
        return getColumnNames()[column];
    }

    public boolean isCellEditable(int row, int col) {

        //last two columns not editible
        if(col > 1) {
            return false;
        } else {
            return true;
        }
    }

    public boolean isColumnEditable(int col) {

        //last two columns not editible
        if(col > 1) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Creates a new dose and adds it to the table model.
     */
    public void addRow() {
        list.add(new String[]{"row" + count + " val1",
        "row" + count + " val2", "row" + count + " val3"});
        fireTableRowsInserted(list.size() - 1, list.size() - 1);
    }

    public void deleteRow(int row) {

        list.remove(row);

        fireTableRowsDeleted(row, row);
    }

     public Object getValueAt(int rowIndex, int columnIndex) {
         String []row = (String [])list.get(rowIndex);
         return row[columnIndex];
     }

     public void setValueAt(Object updateValue, int rowIndex, int
colIndex) {
         String []row = (String [])list.get(rowIndex);
         row[colIndex] = (String)updateValue;
     }

    /**
     * Returns the array of column names for this table.
     *
     * @return the array of column names for this table.
     */
    public String[] getColumnNames() {
        return columnNames;
    }
}

class JTextFieldTableCellEditor extends AbstractCellEditor
        implements TableCellEditor {

    private JTextField tf = new JTextField();

    public JTextFieldTableCellEditor() {
        super();
    }

    public Object getCellEditorValue() {
        return tf.getText();
    }

    public Component getTableCellEditorComponent(JTable table,
            Object value, boolean isSelected, int row, int column) {

        tf.setText(value.toString());
        tf.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent fe) {
                tf.selectAll();
            }
        });
        tf.selectAll();
        return tf;
    }
}
katjapanisch@yahoo.com - 27 Apr 2007 13:53 GMT
> Can anyone tell me what the problem is? If I remove the row
> tc.setCellEditor(new JTextFieldTableCellEditor()); it doesn't throw the
> exception.

If you select the row by clicking on an editable cell, your cell
editor is not stopped before the row is deleted.
Try stopping the active cell editor in your action listener before
deleting.

deleteButton.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
               int rowNumber = table.getSelectedRow();
               TableCellEditor editor = table.getCellEditor();
               if (editor != null) {
                   editor.stopCellEditing();
               }
               ((TestTableModel)
table.getModel()).deleteRow(rowNumber);
           }
       });

Otherwise, the selection of a new cell after row deletion will stop
the cell editor in the deleted
row, and JTable.editingStopped tries to set the new value for the
edited cell in a row that no longer exists.

If you don't set a custom cell editor, DefaultCellEditor will be used.
Because DefaultCellEditor stops cell editing on actionPerformed,
the exception does not occur.

Katja
Lionel van den Berg - 28 Apr 2007 09:06 GMT
> Otherwise, the selection of a new cell after row deletion will stop
> the cell editor in the deleted
> row, and JTable.editingStopped tries to set the new value for the
> edited cell in a row that no longer exists.

Excellent. Thank you. I've added some new code in my custom JTable to
stop the editing an all is well :).

Thanks

Lionel.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.