Spencer Carlson
Spencer Carlson

Reputation: 19

How to make a JTable with multiple Components?

I have a JTable that I want to apply two prepareRenderer methods to, but I'm not sure how I can apply both.

JTable table = new JTable(model){

        public Component prepareRenderer(TableCellRenderer renderer, int row, int column){
            Component returnComp = super.prepareRenderer(renderer, row, column);
            Color alternateColor = new Color(241, 243, 247);
            Color whiteColor = Color.WHITE;
            if (!returnComp.getBackground().equals(getSelectionBackground())){
                Color bg = (row % 2 == 0 ? alternateColor : whiteColor);
                returnComp .setBackground(bg);
                bg = null;
            }
            return returnComp;
        }


        public Component prepareRenderer2(TableCellRenderer renderer, int rowIndex,
                int columnIndex) {
            JComponent component = (JComponent) super.prepareRenderer(renderer, rowIndex, columnIndex);  

            if(Double.parseDouble(getValueAt(rowIndex, 0).toString()) > (Double.parseDouble(rollReq.getText())) && columnIndex == 6) {
                component.setBackground(Color.RED);
            } else if(Double.parseDouble(getValueAt(rowIndex, 0).toString()) > (Double.parseDouble(rollReq.getText())) && columnIndex == 6){
                component.setBackground(Color.GREEN);
            }
            return component;
        }

    };`

The first one is to make one row white, and the next row grey, for easier readability. And the second one is to change the cell color of a column based on it's value.

Any help would be appreciated.

Thank you!

Upvotes: 1

Views: 172

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347332

This is known as "candy stripping" (and a few others) and prepareRenderer is a poor choice for implementing it (IMHO) as it potentially overrides any logic which the renderer might have otherwise been trying to convy (and I just don't like it :P). You could have a look at this alternative

I'm not a fan of using PrepareRenderer, it has the potential to override the prescribed logic of the cell renderer, which as a developer, would have me cursing you for screwing with me

Much of the functionality would actually be better suited to a custom cell renderer, but candy stripping is somewhat complex.

In your case, you NEED to call your custom methods from the prepareRenderer method, because no one else is going to do it for you

public Component prepareRenderer(TableCellRenderer renderer, int row, int column){
    Component returnComp = super.prepareRenderer(renderer, row, column);
    prepareRowRenderer(returnComp, row);
    prepareColumnRenderer(returnComp, col);
    return returnComp;
}

protected void prepareRowRenderer(Component returnComp, int row) {
    Color alternateColor = new Color(241, 243, 247);
    Color whiteColor = Color.WHITE;
    if (!returnComp.getBackground().equals(getSelectionBackground())){
        Color bg = (row % 2 == 0 ? alternateColor : whiteColor);
        returnComp .setBackground(bg);
        bg = null;
    }
}


public Component prepareColumnRenderer(TableCellRenderer renderer, int columnIndex) {
    if(Double.parseDouble(getValueAt(rowIndex, 0).toString()) > (Double.parseDouble(rollReq.getText())) && columnIndex == 6) {
        component.setBackground(Color.RED);
    } else if(Double.parseDouble(getValueAt(rowIndex, 0).toString()) > (Double.parseDouble(rollReq.getText())) && columnIndex == 6){
        component.setBackground(Color.GREEN);
    }
    return component;
}

Upvotes: 2

camickr
camickr

Reputation: 324207

The first one is to make one row white, and the next row grey, for easier readability. And the second one is to change the cell color of a column based on it's value.

Not sure why you think you need two prepareRenderers. Just merge the logic into one:

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

    //  Color row based on a cell value

    if (!isRowSelected(row))
    {
        //c.setBackground(getBackground()); //removed
        c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY); // added
        int modelRow = convertRowIndexToModel(row);
        String type = (String)getModel().getValueAt(modelRow, 0);

        if ("Buy".equals(type)) c.setBackground(Color.GREEN);
        if ("Sell".equals(type)) c.setBackground(Color.YELLOW);
    }

    return c;
}

The above code was "combined" from the "Data Example" found in Table Row Renderring.

So all you need to do is slightly restructure your code using the above structure:

  1. check if row is selected
  2. set the alternating color background
  3. override alternating color with data based check for background color

Also, you should not use columnIndex. The user may have reordered the columns.

(Double.parseDouble(getValueAt(rowIndex, 0).toString()) >
    (Double.parseDouble(rollReq.getText())) && columnIndex == 6) 

Instead you should use:

int modelColumn convertColumnIndexToModel(columnIndex));
(Double.parseDouble(getValueAt(rowIndex, 0).toString()) >
    (Double.parseDouble(rollReq.getText())) && modelColumn == 6) 

For the same reason you should not use: getValueAt(rowIndex, 0). Again the column may be moved.

Upvotes: 2

Related Questions