setCellRenderer for specific cell in JTable?

  • Follow


Hi,
I'm working on JTable ->HTML Table representations and I'm trying to
figure out how to set a CellRenderer for a specific cell, rather than
for the entire column.
For example, JTable.setDefaultRenderer(ImageIcon.class, new
MyImageIconRenderer()) will work if I want the entire column to be
rendered using that renderer, but is there a way that I can specify a
cell renderer for a specific cell as opposed to the entire column?

The idea is when some body creates an HTML table, the data isn't always
of the same type in a certain column, so I'd like to be able to grab
the class of a specific cell, then render it using the renderer I've
created for that class.

If anything else is needed to make my question more clear, feel free to
ask!

Thanks in advance

0
Reply terpatwork (3) 12/1/2006 10:20:03 AM

terpatwork@hotmail.com wrote:
> Hi,
> I'm working on JTable ->HTML Table representations and I'm trying to
> figure out how to set a CellRenderer for a specific cell, rather than
> for the entire column.
> For example, JTable.setDefaultRenderer(ImageIcon.class, new
> MyImageIconRenderer()) will work if I want the entire column to be
> rendered using that renderer, but is there a way that I can specify a
> cell renderer for a specific cell as opposed to the entire column?
>
> The idea is when some body creates an HTML table, the data isn't always
> of the same type in a certain column, so I'd like to be able to grab
> the class of a specific cell, then render it using the renderer I've
> created for that class.
>
> If anything else is needed to make my question more clear, feel free to
> ask!
>
> Thanks in advance

This is easily solved by creating a renderer which delegate work to
other renderers based on the class of the passed value.

Here's some code doing exactyle this:

/*
 * Author: Bart Cremers
 * Date: 1-dec-2006
 * Time: 12:26:24
 */
package quick;

import javax.swing.table.TableCellRenderer;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.HashMap;
import java.util.Date;

public class MultiRenderer implements TableCellRenderer {
    private TableCellRenderer defaultRenderer = new
DefaultTableCellRenderer();

    private Map<Class, TableCellRenderer> registeredRenderers = new
HashMap<Class, TableCellRenderer>();

    public Component getTableCellRendererComponent(JTable table, Object
value, boolean isSelected, boolean hasFocus,
                                                   int row, int column)
{
        TableCellRenderer delegate = null;
        if (value != null) {
            delegate = getDelegate(value.getClass());
        }

        if (delegate == null) {
            delegate = defaultRenderer;
        }

        return delegate.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
    }

    public void registerRenderer(Class type, TableCellRenderer
renderer) {
        registeredRenderers.put(type, renderer);
    }

    private TableCellRenderer getDelegate(Class type) {
        TableCellRenderer delegate = null;
        while (type != null && delegate == null) {
            delegate = registeredRenderers.get(type);
            type = type.getSuperclass();
        }
        return delegate;
    }

    /* Sample code */
    private static final Object[] colNames = new Object[] {
        "A", "B", "C"
    };
    private static final Object[][] rowData = new Object[][] {
        new Object[] { 1, "Test", null },
        new Object[] { 2, 20, "Foo" },
        new Object[] { 3, 10, 10 },
        new Object[] { 4, true, false },
        new Object[] { 5, false, "Bar" },
        new Object[] { 6, new Date(), true },
        new Object[] { 7, 10, new Date() },
    };

    public static void main(String[] args) {
        JFrame f = new JFrame();

        JTable table = new JTable(rowData, colNames);

        MultiRenderer multiRenderer = new MultiRenderer();
        multiRenderer.registerRenderer(Boolean.class,
table.getDefaultRenderer(Boolean.class));
        multiRenderer.registerRenderer(Date.class,
table.getDefaultRenderer(Date.class));
        multiRenderer.registerRenderer(Number.class,
table.getDefaultRenderer(Number.class));


table.getColumnModel().getColumn(1).setCellRenderer(multiRenderer);

table.getColumnModel().getColumn(2).setCellRenderer(multiRenderer);

        f.add(new JScrollPane(table), BorderLayout.CENTER);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
    /* End sample code */
}


Regards,

Bart

0
Reply Bart 12/1/2006 11:49:03 AM


That does just what I was looking for.  Thanks a million!

0
Reply terpatwork 12/1/2006 12:31:35 PM

Bart Cremers wrote:
> terpatwork@hotmail.com wrote:
> > Hi,
> > I'm working on JTable ->HTML Table representations and I'm trying to
> > figure out how to set a CellRenderer for a specific cell, rather than
.............................
>     }
>     /* End sample code */
> }
>
>
> Regards,
>
> Bart

That's very nice solution, but there is too many code in one class :)
what about another solution:

Making many single renderers for each cell type, then overriding
JTable.getCellRenderer(int,int) - overriden function should return
specific renderer ;)

I use this method because it's much cleaner

0
Reply Nickolay 12/4/2006 3:45:57 AM

Nickolay Cherkezishvili wrote:
> Bart Cremers wrote:
> > terpatwork@hotmail.com wrote:
> > > Hi,
> > > I'm working on JTable ->HTML Table representations and I'm trying to
> > > figure out how to set a CellRenderer for a specific cell, rather than
> ............................
> >     }
> >     /* End sample code */
> > }
> >
> >
> > Regards,
> >
> > Bart
>
> That's very nice solution, but there is too many code in one class :)
> what about another solution:
>
> Making many single renderers for each cell type, then overriding
> JTable.getCellRenderer(int,int) - overriden function should return
> specific renderer ;)
>
> I use this method because it's much cleaner

I can't see where there are to many lines in one class. Dropping the
sample code from the renderer you're left with 25 lines of code, which
is a rather small class in my opinion.

There are two reason why I wouldn't go for overriding getCellRenderer
in this case. First, the cellrenderer returned should be specified by
the class of the value. It's much cleaner to go through a renderer
subclass in this case.
The second is, I simply don't like to subclass Swing components unless
there is no other way. 

Regards,

Bart

0
Reply Bart 12/4/2006 7:45:07 AM

Imagine that your project is grown up to 30000 code lines, and you have
many different JTables with many different renderers. Than you will see
that my method is better, because it makes program logic easier to
understand by other programmers. Besides - in most cases it's better to
make your own JTable class by overriding original JTable. It's much
better to customize JTable and use it in your project.

This is my own opinion :)

0
Reply Nickolay 12/4/2006 12:15:28 PM


On Dec 4, 1:15 pm, "Nickolay Cherkezishvili" <nickol...@gmail.com>
wrote:
> Imagine that your project is grown up to 30000 code lines, and you have
> many different JTables with many different renderers. Than you will see
> that my method is better, because it makes program logic easier to
> understand by other programmers. Besides - in most cases it's better to
> make your own JTable class by overriding original JTable. It's much
> better to customize JTable and use it in your project.
>
> This is my own opinion :)

I'm not going to discuss if your method is better or not. That's
probably a matter of taste. Could you show (or point me) to some sample
code to prove your point? I can't imagine on how you implement this
cleaner by overriding JTable.

I can easily imagine 30000 code lines in my projects by the way, as I'm
working on 500,000+ code lines projects for the past 7 years :)

Bart

0
Reply Bart 12/4/2006 1:55:45 PM

Bart Cremers wrote:
> On Dec 4, 1:15 pm, "Nickolay Cherkezishvili" <nickol...@gmail.com>
> wrote:
(snip)....
> > This is my own opinion :)
....
> ...Could you show (or point me) to some sample
> code to prove your point?

Aaaah.  " let the code do the talkin' "?
Good suggestion.

I would especially like to see a self contained example
of the alternate method, since part of the claim is that
the other method is (WTE) 'neater and cleaner'..

Andrew T.

0
Reply Andrew 12/4/2006 2:48:25 PM

package kolya;

import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class TableProbe1 extends JTable {

	@Override
	public TableCellRenderer getCellRenderer(int row, int column) {

		// You may call getValueAt method from TableModel
                // and get the class of returned value

		return super.getCellRenderer(row, column);
	}

	@Override
	public TableCellEditor getCellEditor(int row, int column) {

		// Do the same thing as in getCellRenderer to check class type
		return super.getCellEditor(row, column);
	}

}

Then make multiple renderers and editors and just return them from
these functions.
As you may see there is no any logic related to class delegation (as it
were in last sample). 

I think this method much easier to understand ;)

0
Reply Nickolay 12/5/2006 1:41:27 AM

8 Replies
212 Views

(page loaded in 0.117 seconds)

Similiar Articles:













7/24/2012 8:49:17 PM


Reply: