Pyromanci
Pyromanci

Reputation: 547

Custom TableCellEditor only working on 1 Column Dispite applied to all

I have a rather complex JTable I'm working on. The number of rows and columns are build off a list. Then depending on what column of what row the cell editor needs to change out. While Goggling for a solution I found this: http://www.java2s.com/Code/Java/Swing-Components/EachRowwithdifferentEditorExample.htm

I took that code as it was and run it just to make sure it was working the current Java versions and it did. So i worked it into my JTable i had already build, but what seems to be happening is when I go to apply it to multiple columns it only ends up working for the first column.

I put together a fully executable section of code that I have commented and set up to simulate my database data. The code is pretty decently commented so should be easy to follow. This sample does at least for me still produces the problem.

If any of you can see whats wrong I would greatly appreciate the help.

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;


public class EachRowEditorExample extends JFrame {

    public EachRowEditorExample() {
        super("EachRow Editor Example");
        List<Membership> _Memberships = new ArrayList<Membership>();
        DefaultTableModel DataModel;

        //Lets Start by simluating the data.
        for (int z = -2; z < 10; z++)
        {
            Membership m = new Membership();
            m.setId(z);
            if (z == -2) 
            {
                m.setMembership("Employee");
                m.setEft(false);
            }
            else if (z == -1) 
            {
                m.setMembership("NONE");
                m.setEft(false);
            }
            else
            {
                m.setMembership("Membership " + z);
                if (z < 3 )
                    m.setEft(true);
                else
                    m.setEft(false);
            }
            _Memberships.add(m);
        }

        //*******************************************************
        // Starts Copy and paste from Program
        //*******************************************************
        //lets build our Data Model
        int size = _Memberships.size(); 
        Object[][] rows = new Object[size][];
        String[] cols = new String[size];
        int x = 0;
        for(Iterator<Membership> i = _Memberships.iterator(); i.hasNext(); )
        {
            Membership side = i.next();
            cols[x] = side.getMembership();
            Object[] row = new Object[size];
            int b = 0;
            for(Iterator<Membership> j = _Memberships.iterator(); j.hasNext(); )
            {
                Membership top = j.next();
                if (side.getId() == top.getId() && (side.isEft() && top.isEft()))
                {
                    row[b] = null;
                }
                else
                    row[b] = NUHPADX(side.getId(), top.getId());
                b++;
            }
            rows[x] = row;
            x++;
        }
        DataModel = new DefaultTableModel(rows,cols);


        //Now Lets create our JTable and configure it.
        JTable table = new JTable(DataModel) {
            @Override
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                Object t = getValueAt(rowIndex, rowIndex);
                if (t == null)
                    return false;
                else
                    return true;
            }

            @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
            {
                Component c = super.prepareRenderer(renderer, row, column);

                Object t = getValueAt(row, column);
                if (t == null)
                {
                    c.setBackground(Color.black);
                }
                else
                {
                    Color PRIMARY_ROW_COLOR = Color.white; 
                    Color ALTERNATE_ROW_COLOR = new Color(0xA9F1ED);

                    //even index, selected or not selected
                    if (row % 2 == 0) 
                    {
                        if (column % 2 == 0) 
                            c.setBackground(PRIMARY_ROW_COLOR.darker());
                        else
                            c.setBackground(PRIMARY_ROW_COLOR);
                    }
                    else 
                    {
                        if (column % 2 == 0) 
                            c.setBackground(ALTERNATE_ROW_COLOR.darker());
                        else
                            c.setBackground(ALTERNATE_ROW_COLOR);
                    }
                }
                return c;
            }

        };
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.getTableHeader().setReorderingAllowed(false);
        JList rowHeader = new JList(cols);
        rowHeader.setCellRenderer(new RowHeaderRenderer(table));

        //Lets Place the new table in a Scroll Pane Since there could be alot of data.
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setRowHeaderView(rowHeader);
        getContentPane().add(scrollPane, BorderLayout.CENTER);

        //Now lets Build the Cell Editors
        int c = 0;
        int r = 0;
        for(Iterator<Membership> a = _Memberships.iterator(); a.hasNext();)
        {
            Membership top = a.next();
            EachRowEditor rowEditor = new EachRowEditor(table);
            for(Iterator<Membership> b = _Memberships.iterator(); b.hasNext();)
            {
                Membership side = b.next();

                if (side.getId() == top.getId() && (side.isEft() && top.isEft()))
                {
                    //rowEditor.setEditorAt(r, null);
                }
                else if (side.getId() != top.getId() && (side.isEft() && top.isEft()))
                {
                    NuhpadxCell t = new NuhpadxCell(side, top, new DefaultComboBoxModel(new String[] {"N", "U", "D", "A"}));
                    t.setSelectedItem(NUHPADX(side.getId(), top.getId()));
                    rowEditor.setEditorAt(r, new DefaultCellEditor(t));
                }
                else 
                {
                    NuhpadxCell t = new NuhpadxCell(side, top, new DefaultComboBoxModel(new String[] {"N", "A", "H", "X", "P"}));
                    t.setSelectedItem(NUHPADX(side.getId(), top.getId()));
                    rowEditor.setEditorAt(r, new DefaultCellEditor(t));
                }
                r++;
            }
            table.getColumn(top.getMembership()).setCellEditor(rowEditor);
            table.revalidate();
            c++;
        }

        table.removeColumn(table.getColumn("NONE"));

        //*******************************************************
        // Ends Copy and paste from Program
        //*******************************************************
        setSize(1060, 600);
        setVisible(true);
    }

    //This function jsut simluates a entire class
    public String NUHPADX(int side, int top)
    {
        Random generator = new Random();
        int roll = generator.nextInt(7);
        switch (roll)
        {
            case 0:
                return "N";
            case 1:
                return "U";
            case 2:
                return "H";
            case 3:
                return "P";
            case 4:
                return "A";
            case 5:
                return "P";
            case 6:
                return "A";
            default:
                return "N";
        }

    }

    public static void main(String[] args) {
        EachRowEditorExample frame = new EachRowEditorExample();
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

//Example from http://www.crionics.com/products/opensource/faq/swing_ex/SwingExamples.html
/* (swing1.1.1) */
class EachRowEditor implements TableCellEditor {
    protected Hashtable editors;

    protected TableCellEditor editor, defaultEditor;

    JTable table;

    /**
     * Constructs a EachRowEditor. create default editor
     * 
     * @see TableCellEditor
     * @see DefaultCellEditor
     */
    public EachRowEditor(JTable table) {
        this.table = table;
        editors = new Hashtable();
        defaultEditor = new DefaultCellEditor(new JTextField());
    }

    /**
     * @param row
     *            table row
     * @param editor
     *            table cell editor
     */
    public void setEditorAt(int row, TableCellEditor editor) {
        editors.put(new Integer(row), editor);
    }

    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        editor = (TableCellEditor) editors.get(new Integer(row));
        if (editor == null) {
            editor = defaultEditor;
        }
        return editor.getTableCellEditorComponent(table, value, isSelected, row, column);
    }

    public Object getCellEditorValue() {
        return editor.getCellEditorValue();
    }

    public boolean stopCellEditing() {
        return editor.stopCellEditing();
    }

    public void cancelCellEditing() {
        editor.cancelCellEditing();
    }

    public boolean isCellEditable(EventObject anEvent) {
        selectEditor((MouseEvent) anEvent);
        return editor.isCellEditable(anEvent);
    }

    public void addCellEditorListener(CellEditorListener l) {
        editor.addCellEditorListener(l);
    }

    public void removeCellEditorListener(CellEditorListener l) {
        editor.removeCellEditorListener(l);
    }

    public boolean shouldSelectCell(EventObject anEvent) {
        selectEditor((MouseEvent) anEvent);
        return editor.shouldSelectCell(anEvent);
    }

    protected void selectEditor(MouseEvent e) {
        int row;
        if (e == null) {
            row = table.getSelectionModel().getAnchorSelectionIndex();
        } else {
            row = table.rowAtPoint(e.getPoint());
        }
        editor = (TableCellEditor)editors.get(new Integer(row));
        if (editor == null) {
            editor = defaultEditor;
        }
    }
}

//*******************************************************
// Starts Copy and paste from Program
//*******************************************************
class RowHeaderRenderer extends JLabel implements ListCellRenderer {
    private static final long serialVersionUID = 4619707414623897299L;

    public RowHeaderRenderer(JTable table) {
        JTableHeader header = table.getTableHeader();
        setOpaque(true);
        setBorder(UIManager.getBorder("TableHeader.cellBorder"));
        setHorizontalAlignment(CENTER);
        setForeground(header.getForeground());
        setBackground(header.getBackground());
        setFont(header.getFont());
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        setText((value == null) ? "" : value.toString());
        return this;
    }
}

class NuhpadxCell extends JComboBox {
    private static final long serialVersionUID = -4464709511574911230L;

    private Membership _side;
    private Membership _top;

    public NuhpadxCell(Membership s, Membership t, DefaultComboBoxModel aModel)
    {
        _side = s;
        _top = t;
        addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                DoUpdate();
            }

        });

        setModel(aModel);
    }

    private void DoUpdate() {
        // I would then update my database useing the ID of the side and top memberships as keys.
    }
}

//*******************************************************
// Ends Copy and paste from Program
//*******************************************************

//A bare Skeleton of the membership class needed to run this code.
class Membership {

    protected int id;
    protected String membership;
    protected boolean eft;

    public int getId() {
        return id;
    }
    public void setId(int value) {
        this.id = value;
    }

    public String getMembership() {
        return membership;
    }
    public void setMembership(String value) {
        this.membership = value;
    }

    public boolean isEft() {
        return eft;
    }
    public void setEft(boolean value) {
        this.eft = value;
    }
}

Upvotes: 2

Views: 2205

Answers (2)

Guillaume Polet
Guillaume Polet

Reputation: 47607

Your solution seems awfully complicated for something that looks quite simple. You actually only have two different CellEditor which are both based on a JComboBox.

So, a simpler solution would be to extend DefaultCellEditor with a JComboBox and override getTableCellEditorComponent(), depending on which row you are on, you update the JComboBox with the appropriate model and you return the call to super.

Eventually, you set this cell editor on all your columns of the table.

Also consider following Java coding conventions (variables and methods starts with a lower case letter, classes starts with an upper case letter, etc...)

EDIT:

    class MyTableCellEditor extends DefaultCellEditor {
        private DefaultCellEditor defaultEditor;
        private DefaultComboBoxModel nudaModel = new DefaultComboBoxModel(new String[] { "N", "U", "D", "A" });
        private DefaultComboBoxModel nahxpModel = new DefaultComboBoxModel(new String[] { "N", "A", "H", "X", "P" });

        public MyTableCellEditor() {
            super(new JComboBox());
            defaultEditor = new DefaultCellEditor(new JTextField());
        }

        private JComboBox getComboBox() {
            return (JComboBox) editorComponent;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            Membership top = _Memberships.get(column);
            Membership side = _Memberships.get(row);

            if (side.getId() == top.getId() && side.isEft() && top.isEft()) {
                return defaultEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
            } else if (side.getId() != top.getId() && side.isEft() && top.isEft()) {
                getComboBox().setModel(nudaModel);
            } else {
                getComboBox().setModel(nahxpModel);
            }
            return super.getTableCellEditorComponent(table, NUHPADX(side.getId(), top.getId()), isSelected, row, column);
        }
    }

And here is implementation of what your TableModel could look like:

    class MyDataModel extends AbstractTableModel{

        @Override
        public int getRowCount() {
            return _Memberships.size();
        }

        @Override
        public int getColumnCount() {
            return _Memberships.size();
        }

        @Override
        public String getColumnName(int column) {
            // Here feel free to return the appropriate column names.
            return super.getColumnName(column);
        }

        @Override
        public Object getValueAt(int row, int column) {
            return NUHPADX(_Memberships.get(row).getId(), _Memberships.get(column).getId());
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            // Here you can do whatever you want to say that is editable or not
            // If it is editable, you need to override setValueAt
            return true;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            // Here you need to implement the update of your model
        }

    }

Upvotes: 3

mKorbel
mKorbel

Reputation: 109823

1.issue came from code line,

table.removeColumn(table.getColumn("NONE"));

2.then JTables view returns different column index as are stored into TableModel, you have to call table.convertColumnIndexToModel() in the prepareRenderer and Editor too

3.remove isCellXxx from JTable to the Model e.i.

DataModel = new DefaultTableModel(rows, cols) {

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        Object t = getValueAt(rowIndex, rowIndex);
        if (t == null) {
            return false;
        } else {
            return true;
        }
    }
};

4.call table.setPreferredScrollableViewportSize(table.getPreferredSize()); then you can to change setSize(1060, 600); to pack();

5.add there setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); too

6.don't extends JFrame, create an local variable

7.then your main class should be including InitialThread

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            EachRowEditorExample frame = new EachRowEditorExample();
        }
    });
}

EDIT

1, I just wanted to hide that column not actually completely remove it from the Model, which is what that code should be doing (according to Java Docs).

table.removeColumn(table.getColumn("NONE")); remove concrete Column only from JTables View more in the API and JTables tutorial, this Column is still presents in the XxxTableModel, better would be to test that on your side

as for 2, not sure why that really applies.

this is already answered, more is described in the JTable tutorial (read the next section too)

Upvotes: 2

Related Questions