Page 1 of 1

Java - Prevent Individual Cell Selections in JTable?

Posted: Sat Feb 03, 2007 2:45 pm
by Chris Corbyn
Image

Trying to build a date picker for Swing. See those blank cells either side of the numbers? Well, you shouldn't be able to select them because they don't represent anything usable. I can't seem to find any way to disable just specific cells in a JTable. I tried this in my cell renderer but it doesn't work :(

Code: Select all

        public Component getTableCellRendererComponent(
                JTable tbl, Object v, boolean isSelected, boolean isFocused, int row, int col)
        {
                this.tbl = tbl;
                if ((String)v == "")
                {
                        isSelected = false;
                }

// ... snip ...
                return super.getTableCellRendererComponent(tbl, v, isSelected, isFocused, row, col);
}
No response from Java forum as yet so thought I'd throw it to you guys :)

Posted: Sat Feb 03, 2007 4:32 pm
by Chris Corbyn
I just did this for now. Disabled the cells, but put last month's numbers in them. You can still select the cells which isn't what I wanted but they don't highlight. Either way, it will alow my stuff to work as expected.

Image

Posted: Wed Feb 07, 2007 3:15 am
by Chris Corbyn
The correct way to do this was to override the JTable class' changeSelection() method to check the value before actually selecting the cell.

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

/**
 * CalendarTable is a JTable which does not allow empty cells to be selected
 * @author Chris Corbyn
 */
public class CalendarTable extends JTable
{
        /**
         * Ctor
         * @param model The table model to render
         */
        CalendarTable(AbstractTableModel model)
        {
                super(model);
        }
        /**
         * Overridden to prevent empty cells from being selected
         */
        public void changeSelection(int row, int col, boolean toggle, boolean extend)
        {
                if ((String)(this.getValueAt(row, col)) != "")
                        super.changeSelection(row, col, toggle, extend);
        }
}

Posted: Wed Feb 07, 2007 6:09 am
by timvw
In the windowsforms world this problem seems to be tackled as following (reducing the need to subclass a control):

- Before the changeSelection is called, a Selecting event is raised.. and after the call a Selected event is raised...
(the selecting event has a property bool Cancel that allows the user to cancel the operation)

Posted: Wed Feb 07, 2007 8:33 am
by Chris Corbyn
I see... that's a bit like JS. I wondered if a changeListener could be used to do something similar but ChangeEvent has such a basic API it clearly isn't :P

I enhanced the subclass I made and allowed cells to be disabled and enabled by calling a disableCellAt() method now. It means I can actually put numbers in the disabled cells rather than leaving them blank :)

Code: Select all

/*
 * Licensed under the terms of the GNU Lesser General Public License
 * Please read the LICENSE file
 */

package org.w3style.calendar;

import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import java.util.HashMap;

/**
 * CalendarTable is a JTable which allows cells to be disabled
 * @author Chris Corbyn
 */
public class CalendarTable extends JTable
{
        /**
         * A matrix of the disabled cell positions
         */
        protected HashMap<Integer,HashMap<Integer,Boolean>> disabledRows;
        /**
         * Ctor
         * @param model The table model to render
         */
        public CalendarTable(AbstractTableModel model)
        {
                super(model);
                this.disabledRows = new HashMap<Integer,HashMap<Integer,Boolean>>();
        }
        /**
         * Disable a cell selection at the coordinates (row,col)
         * @param row The row of the cell
         * @param col The column of the cell
         */
        public void disableCellAt(int row, int col)
        {
                if (!this.disabledRows.containsKey(row))
                {
                        this.disabledRows.put(row, new HashMap<Integer,Boolean>());
                }
                this.disabledRows.get(row).put(col, true);
        }
        /**
         * Clear out disabled cell statuses
         */
        public void resetCellStates()
        {
                this.disabledRows.clear();
        }
        /**
         * Enable a cell if it has been disabled
         * @param row The row of the disabled cell
         * @param col The column of the disabled cell
         */
        public void enableCellAt(int row, int col)
        {
                if (this.isDisabledAt(row, col))
                        this.disabledRows.get(row).remove(col);
        }
        /**
         * Check if the cell at row,col is disabled
         * @param row The row to test
         * @param col The column to test
         * @return true, if the cell is disabled
         */
        public boolean isDisabledAt(int row, int col)
        {
                if (this.disabledRows.containsKey(row))
                {
                        if (this.disabledRows.get(row).containsKey(col) && this.disabledRows.get(row).get(col))
                        {
                                return true;
                        }
                }

                return false;
        }
        /**
         * Overridden to prevent disabled cells from being selected
         */
        public void changeSelection(int row, int col, boolean toggle, boolean extend)
        {
                if (!this.isDisabledAt(row, col))
                        super.changeSelection(row, col, toggle, extend);
        }
}