Skip to main content

Problem with JRendererLabel and Painting

11 replies [Last post]
paultaylor
Offline
Joined: 2003-12-04

Im trying out JRenderLabel (Using swingx 1.0) for rendering a table cell, the background shoudl be different depending on the value of the cell, what Im finding is that i just use the same instance of JRenderLabel() for all cells and use setPainter() then when the value of one cell is changed the backgrounds of all cells are being painted to match the changed cell.

AFAIK you shold be able to just use one instance of the renderer for all cells.

If I use setbackground() instead of setPainter() it works okay.
If I change the code to create a new JRendererLabel each time then it works okay.

Is this a bug in JRenderLabel or am I misundersanding something ?

heres the code for the renderer, With the two workarounds commented out)

<br />
package com.jthink.jaikoz.cellrenderer;</p>
<p>import com.jthink.jaikoz.celldata.Cell;<br />
import com.jthink.jaikoz.settings.SyncTableProperties;<br />
import com.jthink.jaikoz.text.JaikozIcon;<br />
import org.jdesktop.swingx.renderer.JRendererLabel;</p>
<p>import javax.swing.*;<br />
import java.awt.*;<br />
import java.util.HashMap;<br />
import java.util.Map;</p>
<p>/**<br />
 * Renders the status column, showing an icon to indicate song edit status<br />
 */<br />
public class StatusRenderer extends AbstractTableCellRenderer<br />
{<br />
    private static StatusRenderer instance;</p>
<p>    public StatusRenderer()<br />
    {</p>
<p>    }</p>
<p>    public static StatusRenderer getInstance()<br />
    {<br />
        if(instance==null)<br />
        {<br />
            instance=new StatusRenderer();<br />
        }<br />
        return instance;<br />
    }</p>
<p>    private static Map statusIconMapping = new HashMap (4);<br />
    static<br />
    {<br />
        statusIconMapping.put(Cell.STATUS_UNCHANGED,JaikozIcon.EMPTY.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_EDITED,JaikozIcon.MODIFIED.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_DELETED,JaikozIcon.DELETE.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_MISSING,JaikozIcon.EMPTY.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_PHYSICALLY_DELETED,JaikozIcon.EMPTY.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_CLOSED,JaikozIcon.EMPTY.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_NOT_SUPPORTED,JaikozIcon.EMPTY.getIconSmall());<br />
        statusIconMapping.put(Cell.STATUS_LINK,JaikozIcon.EMPTY.getIconSmall());<br />
    }</p>
<p>    private JRendererLabel      label = new JRendererLabel();</p>
<p>    public JRendererLabel getRenderer()<br />
    {<br />
        return label;<br />
    }</p>
<p>    public Component getTableCellRendererComponent(final JTable table,<br />
                                                   final Object value,<br />
                                                   final boolean isSelected,<br />
                                                   final boolean hasFocus,<br />
                                                   final int row,<br />
                                                   final int column)<br />
    {<br />
        //label = new JRendererLabel();<br />
        cv = (Cell)value;<br />
        getRenderer().setIcon(statusIconMapping.get(cv.getStatus()));<br />
        renderCellSelection(row,value,isSelected,hasFocus);<br />
        return getRenderer();<br />
    }</p>
<p>    /**<br />
     * Setup the Cell Colours dependent on the status of the contents<br />
     *<br />
     * @param row<br />
     * @param value<br />
     * @param isSelected<br />
     * @param hasFocus<br />
     */<br />
    protected void renderCellSelection(int row, final Object value, final boolean isSelected, final boolean hasFocus)<br />
    {<br />
        if (isSelected)<br />
        {<br />
            label.setBackground(selectionBGColour);<br />
        }<br />
        else<br />
        {<br />
            if (SyncTableProperties.isChangeColouring())<br />
            {<br />
                Color colour = StatusColouringHelper.getColour(cv.getStatus());<br />
                if(colour!=null)<br />
                {<br />
                    getRenderer().setPainter(StatusColouringHelper.getStatusPainter(cv.getStatus()));<br />
                    //getRenderer().setBackground(Color.GREEN);</p>
<p>                }<br />
                else<br />
                {<br />
                    setDefaultBackground(getRenderer(),row);<br />
                }<br />
            }<br />
            else<br />
            {<br />
                setDefaultBackground(label,row);<br />
            }<br />
        }<br />
    }<br />
}</p>
<p>

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kleopatra
Offline
Joined: 2003-06-11

Walter,

> See IconHighlighter (looks like LabelProvider doesn't
> support the experimental IconValue converter yet).
>

sure LabelProvider supports IconValue - but if _you_ couldn't find that it's probably not so obvious (a MappedValue is what's needed)

CU
Jeanette

walterln
Offline
Joined: 2007-04-17

Well I don't use SwingX actively so I looked at the Javadoc (first found, swinglabs.org never works for me it seems): http://www.jarvana.com/jarvana/view/org/swinglabs/swingx/1.6.1/swingx-1.6.1-javadoc.jar!/index.html

I see methods to set a StringValue on LabelProvider but nowhere to set a IconValue or MappedValue. Digging a bit deeper I see the default renderer constructors can take an IconValue but those must be using undocumented methods to do it?

kleopatra
Offline
Joined: 2003-06-11

the MappedValue is-a StringValue It's a clutch which never got cleaned ... cough ...

CU
Jeanette

kleopatra
Offline
Joined: 2003-06-11

sure the doc could use a bit effort - feel free to contribute, everybody, after all, it's a wiki and each member of java.net has write access ;-)

The separation line is somewhat like "content" vs. "visual decoration", in SwingX vocabulary that maps to "StringValue" (and Icon- and Boolean- and Mapped- which is the combination of all) which is basically a mapping of cell value into its String/Icon representation vs. "Highlighter". The latter can be conditionally switched on/off - controlled by a HighlightPredicate.

From your snippet assuming that the value is of type Cell, you would need a custom IconValue to map to a state-related icon:

[code]
IconValue iv = new IconValue() {

Map stateIconMap = ...

Icon getIcon(Object value) {
if (value instanceof Cell) {
return stateIconMap.get(value.getState());
}
return IconValues.EMPTY; // or null or whatever
}
}

table.getColumn(...).setCellRenderer(new DefaultTableRenderer(new MappedValue(StringValues.EMPTY, iv);
[/code]

Now on to the visual decoration:

[code]

public static class StatusPredicate implements HighlightPredicate {

@override
boolean isHighlighted(...ComponentAdapter adapter) {
return this.status == getStatus(adapter);
}

private boolean getStatus(ComponentAdapter adapter) {
// check for whereever the status is stored,
// might be the current cell
return adapter.value.getStatus();
// or some other cell in the same row
return adapter.getValue(modelColumn).getStatus();
}
}

// then one Highlighter per state
table.addHighlighter(new ColorHighlighter(new StatusPredicate(oneState), RED, ... );
[/code]

Cheers
Jeanette

kleopatra
Offline
Joined: 2003-06-11

do. not. use. custom. renderer. implementations. DO. USE. HIGHLIGHTERS.

CU
Jeanette

(didn't look into your code - you'r on your own if stray from the recommended path ;-)

paultaylor
Offline
Joined: 2003-12-04

Okay, supplementary questions then.

1. So this is the recommended way using Swingx, (I havent actually seen these recommendations but is does ring a bell) but obviously not for plain Swing (because it doesnt have these highlighters) so what is the reasoning behind this, why is using highlighters on top of renderers rather than just doing the rendering as part of the table rendering calls better. It seems counterintuitive to me because you have some of your rendering logic in one place and some in another.

2. My understanding was (but now must be incorrect) that renderers were used for rendering the cell fixed state (i.e set backgrounf to green because cell has been modified) whereas highters are for overlaying addtional information that coudl be turned on and off as requested by user such as (set background of all invalid values to red)

kleopatra
Offline
Joined: 2003-06-11

Please see the swingx wiki for answers to your questions and links to previous debates

Thanks
Jeanette

paultaylor
Offline
Joined: 2003-12-04

Hmm, if you ever have a minute it would be good if you could complete expand the wiki doscumentation coz it so full of TODOS its hard to understand your argument.

But the summary is that renderer is meant to store what, and highlighter how, but this is a very confusing concept because renderers display things, surely the 'what' is the 2nd parameter passed to getTableCellRendererComponent

So you want to display an icon based on the value in the tablecell, so in Swingx you use a JLabelRenderer as the renderer (because labels can have icons) , but you set the colouring in associated highlighter, but displaying the icon is part of the 'how' isnt it.

walterln
Offline
Joined: 2007-04-17

See IconHighlighter (looks like LabelProvider doesn't support the experimental IconValue converter yet).

As for your original problem, looks like your isSelected case/setDefaultBackground method doesn't reset the Painter.

paultaylor
Offline
Joined: 2003-12-04

Walterin, thanks you are correct about the reset painter, it works now.

As for the Icon Highlighter, if I have threee different icons for threee different status I would need three highlighters then which I could do (though doesnt seem easier), very confused as to what the corresponding TableCellRenderer class should do, it should just return an empty JLabelRenderer() then ?

kleopatra
Offline
Joined: 2003-06-11

>
> doesnt seem easier), very confused as to what the
> corresponding TableCellRenderer class should do, it
> should just return an empty JLabelRenderer() then ?

nothing - you don't interact with any renderer. The SwingX DefaultXXRenderer are legacy glue. The new coins are Highlighter/-Predicate and StringValue.

CU
Jeanette