Link to home
Start Free TrialLog in
Avatar of bjg
bjg

asked on

JTable question...

I am trying to create a JTable which has two columns.  The first column I want to be a JCheckBox (and I want the user to be able to set it checked or unchecked in the table as well as display the cell checked or unchecked depending on the data set that the model contains).  The second column I want to have a JTextField as the CellRenderer but I don't want it to be editable, so it's not a CellEditor, just a CellRenderer.  I also do not want to display the column headers.  How can I do this?
Avatar of bjg
bjg

ASKER

Edited text of question
This is an example of such a table:

        String[] columnNames = {DIRECTORY, FILE_SPEC, IS_RECURSIVE, PARSER_START_STATE, URL_PREFIX};
        DefaultTableModel model = new DefaultTableModel(columnNames, 0)
        {
            public Class getColumnClass(int columnIndex)
            {
                if (columnIndex == 2) // This makes the third column  displayed as a checkbox
                {
                    return (new Boolean(true)).getClass();
                }
                else
                {
                    return super.getColumnClass(columnIndex); // Other columns are labels
                }
            }
        };

        JTable newTable = new JTable(model)
        {
          public boolean isCellEditable(int row, int column)
          {
            return (column != 1);  // This makes the second column non-editable
          }
        };

        newTable.setTableHeader(null); // That should take care of the header
Avatar of bjg

ASKER

How can I make the first column an editable JCheckBox, and the second column a non-editable JTextField?
Avatar of bjg

ASKER

Do I have to create a custom CellRenderer, and a custom CellEditor, and then set each column's editor or renderer appropriately?
Simply replace the literal 2 with literal 0 in the code above. And shorten the list of column names to two entries. The rest stays the same.
Avatar of bjg

ASKER

Do I have to create a custom CellRenderer, and a custom CellEditor, and then set each column's editor or renderer appropriately?
Avatar of bjg

ASKER

How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
Avatar of bjg

ASKER

How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
No, just try the code I supplied, no ther changes should be required. DefaultTableModel and DefaultCellRenderer should take care of all the details.
If the cell is editable, it will use JTextField a cell editor. I am not sure with multiple lines of text, that will probably require a custom renderer/editor.
Avatar of bjg

ASKER

How do I make the other columns JTextFields, rather than JLabels?
I want to support multiple lines of text for each cell (not the JCheckBox cell, but the JTextField cell)
Avatar of bjg

ASKER

I don't want the JTextField cell to be editable, I want the JCheckBox field to be editable or selectable.  The only reason why I want to use the JTextField as the other cell, is so I can support multiple lines of text.  How can I set this up in the table?
I see what you want. Yes, if you want to have a text field as a renderer you have to create one of your own. I am not sure how it solves your problem, beacuse text field as far as I know display only one line of text.

Look at the code of DefaultTableCellRenderer (which extends JLabel) and create something similar by extending JTextField. (Make sure you call setEditable(false)). I think it will look no diffrenet that it looks with the label, but you can try.

To set the new cell editor only for specific column, get a TableColumn object for the desired column and call setCellRenderer().
Avatar of bjg

ASKER

Well, I finally have most of it working.  I have it working how I want, just not looking how I want.  When I tell the first column to be a Boolean and editable, it results in a cell with a selectable checkbox.  This is what I want.  But the default look of the checkbox is centered in the cell, and it does not highlight when you select the row.  How can I change this so that it is in the upper left of the cell and highlights like the rest of the row?
You can change the way check box looks by extending DefaultCellEditor class and overriding getTableCellEditorComponent() method. In that method first check whether editorComponent is a check box (it is a protected member so you can do it). If it is, change its appearance, then call super.getTableCellEditorComponent().
Avatar of bjg

ASKER

I tried that and it didn't work
Avatar of bjg

ASKER

I tried that and it didn't work
Avatar of bjg

ASKER

If I set a custom Editor for the CheckBox column, it only shows that renderer when I select the JCheckBox, and then it shows the default renderer for the CheckBox column after I have selected it.  If I also set a custom renderer, I can't select and deselect the JCheckBox.  How can I get this to work?

Here is my code:

package Lccs.Gui.Awt;

import com.sun.java.swing.*;
import com.sun.java.swing.border.*;
import com.sun.java.swing.table.*;
import java.awt.*;
import java.util.*;

public class CheckBoxTable extends JTable
{
      
    public CheckBoxTable(Object data[][])
    {
        super();
       
        this.data = data;
       
        verifyDataElements();
       
          setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
          setShowHorizontalLines(true);
        setShowVerticalLines(false);
       
        String columns[];
        if (hasCheckBox)
        {
              columns = new String[2];
              columns[0] = "Selection";
              columns[1] = "Information";
        } else
        {
              columns = new String[1];
              columns[0] = "Information";
        }
       
        tableModel = new InnerTableModel(columns, data);
        setModel(tableModel);
       
        setDefaultRenderer(Object.class, new InnerTextFieldCellRenderer());
        //setDefaultRenderer(Boolean.class, new InnerCheckBoxCellRenderer());
        setDefaultEditor(Boolean.class, new InnerCellEditor());

            if (hasCheckBox)
            {
                  TableColumn col = getColumn(columns[0]);
                  col.setWidth(30);
                  col.setMinWidth(30);
                  col.setMaxWidth(30);
            }
            
            setRowHeight(getMeasuredRowHeight());
       
        setTableHeader(null);
        setCellSelectionEnabled(false);
    }
   
    private void verifyDataElements() throws IllegalArgumentException
    {
        if (data[0].length > 1)
        {
              for (int i = 0; i < data.length; i++)
              {
                    if (!(data[i][0] instanceof Boolean))
                    {
                          throw new IllegalArgumentException(
                                "First element of row must be a Boolean Object." );
                    }
              }
                hasCheckBox = true;
        } else
              hasCheckBox = false;
    }
   
    private int getMeasuredRowHeight()
    {
          int tokenCount = 0;
          for (int i = 0; i < data.length; i++)
          {
                String str = null;
                if (hasCheckBox)
                      str = (String)data[i][1];
                else
                      str = (String)data[i][0];
                StringTokenizer tok = new StringTokenizer(str, "\n");
                tokenCount = tok.countTokens();
          }
          return (20 * tokenCount);
    }
   
    public void setData(Object data[][])
    {
          tableModel.setData(data);
          revalidate();
          repaint();
    }
   
   
    //Inner Class - TableModel
      class InnerTableModel extends AbstractTableModel
      {
          String[] columnNames = null;
          Object[][] data = null;

          public InnerTableModel(String columns[], Object data[][])
          {
              this.columnNames = columns;
              this.data = data;
          }

          public void setData(Object newData[][])
          {
                this.data = newData;
          }

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

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

          public String getColumnName(int col)
          {
              return columnNames[col];
          }

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

          public Class getColumnClass(int c)
          {
              return getValueAt(0, c).getClass();
          }

          public boolean isCellEditable(int row, int col)
          {
                if (hasCheckBox)
                {
                      if (col == 0)
                            return true;
                }
                return false;
          }

          public void setValueAt(Object value, int row, int col)
          {
              data[row][col] = value;
          }

      }
   
   
   
      //Inner Class - TableCellRenderer
      class InnerTextFieldCellRenderer extends JTextField implements
                                                  TableCellRenderer
      {
          public InnerTextFieldCellRenderer()
          {
                super();
                setOpaque(true);
                setEditable(false);
                setBorder(new EmptyBorder(0,5,0,5));
          }

          public Component getTableCellRendererComponent(JTable table, Object value,
                                boolean isSelected, boolean hasFocus, int row, int column)
          {
                if (isSelected)
              {
                  setForeground(SystemColor.textHighlightText);
                  setBackground(SystemColor.textHighlight);
              }
              else
              {
                  setBackground(table.getBackground());
                  setForeground(table.getForeground());
              }
                setFont(table.getFont());

                if (value != null)
                {
                      setText(value.toString());
                }

                return this;
          }
      }      //End Inner Class
      
      //Inner Class - TableCellRenderer
      class InnerCheckBoxCellRenderer extends JCheckBox implements
                                                  TableCellRenderer
      {
          public InnerCheckBoxCellRenderer()
          {
                super();
                setOpaque(true);
                setVerticalAlignment(TOP);
                setHorizontalAlignment(LEFT);
          }

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

                  if (isSelected)
              {
                  setForeground(SystemColor.textHighlightText);
                  setBackground(SystemColor.textHighlight);
              }
              else
              {
                  setBackground(table.getBackground());
                  setForeground(table.getForeground());
              }
              
                return this;
          }
      }      //End Inner Class
      
      class InnerCellEditor extends DefaultCellEditor
      {
            InnerCellEditor()
            {
                  super(new JCheckBox());
            }
            
            public Component getTableCellEditorComponent(JTable table, Object value,
                                     boolean isSelected,
                                     int row, int column)
            {

                  ((JCheckBox)editorComponent).setVerticalAlignment(JCheckBox.TOP);
                ((JCheckBox)editorComponent).setHorizontalAlignment(JCheckBox.LEFT);
                  
                  if (isSelected)
                  {
                      editorComponent.setBackground(SystemColor.textHighlightText);
                      editorComponent.setForeground(SystemColor.textHighlight);
                  }
                  else
                  {
                      editorComponent.setBackground(table.getBackground());
                      editorComponent.setForeground(table.getForeground());
                  }

                  return editorComponent;
          }
      }
      
      private boolean                  hasCheckBox;
      private InnerTableModel      tableModel;
      private Object                   data[][];
}

Yes, you should be defining you custome renderer as well. Try setting it using:

table.setDefaultRenderer(Boolean.TYPE, new InnerCheckBoxCellRenderer());

Avatar of bjg

ASKER

I did that and it didn't work, that's why I commented it out.
Sorry, I missed it. What if you disable the check box in your renderer. The problem might stem from the fact that checkbox component used as a renderer receives the mouse events instead of the table.
Avatar of bjg

ASKER

Nope, that didn't work either.  
ASKER CERTIFIED SOLUTION
Avatar of LiliaNesterova
LiliaNesterova

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of bjg

ASKER

I guess you answered my original question, but I already have that part working.  I am just trying to set a custom cell editor and cell renderer for the boolean (JCheckBox) column of the table because I don't like the default look of the JCheckBox in the center, I want the JCheckBox in the upper left hand corner.  So how do I do that?
Avatar of bjg

ASKER

How can I make the JCheckBox column mutually exclusive, so that only one can be selected at a time?