Ryan Elkins
Ryan Elkins

Reputation: 5797

How do you add a border to a row in a Jtable?

I have a Jtable and I want to highlight a row by adding a border to the row. I have extended a DefaultTableCellRenderer and I figure the work needs to be done in the getTableCellRendererComponent method.

I'm guessing that since there doesn't seem to be a concept of a row that I need to create a custom border for the individual cells in the row. Something like a left side, top, and bottom for the first cell, a top and bottom for all the inner cells, and a top, bottom, and right side for the last cell in the row. I'm having problems finding out how to go about actually executing the thought process. I'm not sure how to use the setBorder() method or if that's even the direction I need to take.

Upvotes: 3

Views: 21640

Answers (3)

Katu
Katu

Reputation: 1564

I agree with > camickr the best way to go is to override the prepareRendere method. The following code will create a border for a row with a selected cell:

@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {

Component c = super.prepareRenderer(renderer, row, column);    
JComponent jc = (JComponent)c;

if (isRowSelected(row)){
  int top = (row > 0 && isRowSelected(row-1))?1:2;
  int left = column == 0?2:0;
  int bottom = (row < getRowCount()-1 && isRowSelected(row + 1))?1:2;
  int right = column == getColumnCount()-1?2:0;

  jc.setBorder(BorderFactory.createMatteBorder(top, left, bottom, right, this.getSelectionBackground())); 
}
else
  jc.setBorder(null);

return c;
}

Upvotes: 1

camickr
camickr

Reputation: 324207

I would not create a custom renderer for this. Yes it will work if all your data is of the same type. But what happens when you start to mix Strings, with Dates and Integers and Booleans which all use different renderers? Then you would need to create 4 custom renderers.

The better approach is to override the prepareRenderer(...) method JTable so you can add the code in one place. Here is an example to get you started. In reality you would want to use a CompoundBorder that contains a MatteBorder for the top/bottom and and EmptyBorder for the left/right and you would create a single instance of the Border.

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import javax.swing.border.*;

public class TablePrepareRenderer extends JFrame
{
    JTable table;

    public TablePrepareRenderer()
    {
        Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"};
        Object[][] data =
        {
            {"Buy", "IBM", new Double(1000), new Double(80.5), Boolean.TRUE},
            {"Sell", "MicroSoft", new Double(2000), new Double(6.25), Boolean.TRUE},
            {"RSell", "Apple", new Double(3000), new Double(7.35), Boolean.TRUE},
            {"Buy", "Nortel", new Double(4000), new Double(20), Boolean.TRUE}
        };

        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        table = new JTable( model )
        {
            //  Returning the Class of each column will allow different
            //  renderers to be used based on Class

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

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

                //  Color row based on a cell value
                //  Alternate row color

                if (!isRowSelected(row))
                    c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);
                else
                    jc.setBorder(new MatteBorder(1, 0, 1, 0, Color.RED) );


                //  Use bold font on selected row

                return c;
            }
        };

        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.changeSelection(0, 0, false, false);
        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );
    }

    public static void main(String[] args)
    {
        TablePrepareRenderer frame = new TablePrepareRenderer();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

Upvotes: 9

broschb
broschb

Reputation: 5006

You have the correct idea in mind, you will need to set the border on the label in the cellrenderer depending on where it is in the table(i.e. edge, center etc).

Take a look at matteborder. You can specify which areas to draw a border along w/ width and color.

Upvotes: 2

Related Questions