How to prevent using custom cell renderer from disabling row selection?

Hi again,

As thread's title says, is there a way to enable row selection in JTable when I use custom cell renderer? When I use custom cell renderer row selection (as well as any other selection) seems to be disabled...

Here's sample code that shows what I mean:

import java.awt.*;

import javax.swing.*;

import javax.swing.table.*;

class CellRenderextends JLabelimplements TableCellRenderer{

JFrame frame;

JPanel panel;

JTable table;

JScrollPane scrollPane;

publicstaticvoid main(String[] args){

CellRender cr =new CellRender();

}

CellRender(){

frame =new JFrame();

frame.setLocation(300, 300);

frame.setTitle("Test app");

frame.setPreferredSize(new Dimension(450, 450));

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

panel =new JPanel();

table = createTable();

scrollPane =new JScrollPane(table);

panel.add(scrollPane);

frame.add(panel);

frame.pack();

frame.setVisible(true);

}

public JTable createTable(){

String columns[] ={"Col A","Col B"};

String data[][] ={{"A","B"},{"C","D"}};

DefaultTableModel model =new DefaultTableModel(data, columns);

JTable table =new JTable(model);

TableColumn column =null;

for (int i = 0; i < 2; i++){

column = table.getColumnModel().getColumn(i);

// if I comment this line and use default renderer there's no problem with selecting rows

column.setCellRenderer(this);

}

table.setCellSelectionEnabled(true);

return table;

}

public Component getTableCellRendererComponent(JTable table, Object value,

boolean isSelected,boolean hasFocus,int rowIndex,int colIndex){

setText(value.toString());

setBorder(BorderFactory.createMatteBorder(0, 7, 0, 0, Color.GREEN));

if (isSelected)

{

setBackground(Color.RED);

setForeground(table.getSelectionForeground());

}

else

{

setBackground(Color.BLUE);

setForeground(table.getForeground());

}

returnthis;

}

}

[4106 byte] By [Jimzya] at [2007-11-27 4:49:55]
# 1

Well, the problem is that by default JLabel is non-opaque, so the background never gets painted. So you need to make the label opaque.

However, that is not the solution I recommend. There is no real need to create a custom renderer. You can use the table method to get the default renderer and then simply add your Border to the renderer. Then you use the setSelectedBackground() method to set the color of the background. Don't create new classes when you can change the properties of existing classes. Also, the default cell renderer has been optimized to improve painting performance.

camickra at 2007-7-12 10:03:05 > top of Java-index,Desktop,Core GUI APIs...
# 2

Aight, let's foget about external class then.

I'm trying to do what you suggested, but it's going rather poorly...

Changed my custom renderer line to this (not sure if that's what you meant):

for (int j = 0; j<rows; j++)

for (int j = 0; j><rows; j++) {

for (int j = 0; j><rows; j++) {

((JLabel) (table.getCellRenderer(j, i)).getTableCellRendererComponent(

table, table.getValueAt(j, i), false, false, j, i)).setBorder(BorderFactory.createLineBorder(Color.RED, 1));

((JLabel) (table.getCellRenderer(j, i)).getTableCellRendererComponent(

table, table.getValueAt(j, i), false, false, j, i)).setFont(new Font("Arial", Font.BOLD, 10));

((JLabel) (table.getCellRenderer(j, i)).getTableCellRendererComponent(

table, table.getValueAt(j, i), false, false, j, i)).setBackground(Color.RED);

}

It looks awfull and isn't working what is even worse (background color is changing, but border, font... they don't).

Any sample code how to do it correct?>

Jimzya at 2007-7-12 10:03:05 > top of Java-index,Desktop,Core GUI APIs...
# 3

Well, now I'm not exactly sure what you are trying to do so maybe I made a bad suggestion. You don't assign a renderr for each cell, which is what your code appears to be doing.

I was suggesting something like this:

table.setSelectionForeground(....);

table.setSelectionBackground(...);

table.setFont(....);

The default renderer will pick up all those values and apply them to the renderer.

The only complication would be the Border would need to be set separately:

((JLabel)table.getDefaultRenderer(String.class)).setBorder(....);

camickra at 2007-7-12 10:03:05 > top of Java-index,Desktop,Core GUI APIs...
# 4

Okay, those methods helped -- selection works.

However,

((JLabel)table.getDefaultRenderer(String.class)).setBorder(...);

...doesn't appear to be working, no matter which border I choose.

I'm also not able to set tooltips for each cell separately (which was possible using external class) -- can this be done without using renderer class?

One more thing I wanted to ask about, when I use custom table editor on each column, double click to edit is also gone, cells get ready to editing after single mouse click -- something can be done to set it back to normal? (1click = selection, 2 clicks = editing).

Also, is there a way to remove the little border from selected cell?

Thanks for help!

Jimzya at 2007-7-12 10:03:05 > top of Java-index,Desktop,Core GUI APIs...
# 5

> doesn't appear to be working, no matter which border I choose.

Oops, that right. The default renderer resets the border depending of whether the cell has focus or not, so that suggestion won't work.

That means you will need to either:

a) create a custom renderer as you tried before. Here is a better example of what you need to do:

class SomeRenderer extends DefaultTableCellRenderer

{

public Component getTableCellRendererComponent(

JTable table, Object value, boolean isSelected,

boolean hasFocus, int row, int column)

{

super.getTableCellRendererComponent(table,

value, isSelected, hasFocus, row, column);

setBorder (BorderFactory.createBevelBorder (EtchedBorder.RAISED));

return this;

}

}

b) or, you could override the prepareRenderer(...) method of JTable. This method is call after the default renderer values have already been set, so you can override any value here. This posting shows a simple example:

http://forum.java.sun.com/thread.jspa?forumID=57&threadID=613783&start=4

> when I use custom table editor on each column, double click to edit is also gone,

Read the DefaultCellEditor API. There is a method that allows you to control the number of mouse clicks to start editing.

> Also, is there a way to remove the little border from selected cell?

Remove the Border from the editing component.

> I'm also not able to set tooltips for each cell separately -- can this be done without using renderer class?

You can override the getToolTipText() method of JTable. Simple example:

http://forum.java.sun.com/thread.jspa?forumID=57&threadID=676742

Assuming all your data is of the same type (ie. all Strings) then it is probably easier to just create a custom renderer for the Border and tooltip text as you initially tried to do.

However, if you need the same type of logic and you table has columns with different data, then overriding the prepareRenderer() and getToolTipText() methods would be the easier approach.

camickra at 2007-7-12 10:03:05 > top of Java-index,Desktop,Core GUI APIs...