Skip to main content

JXTable and dealing with DefaultTableCellRenderer problems

32 replies [Last post]
cupofjoe
Offline
Joined: 2003-08-05
Points: 0

I've been reading the threads on this since yesterday.

It looked like someone was going to create a JX version of DefaultTableCellRenderer.

I like the 'what' and 'how' seperation. I just can't seem to 'easily' get my objects to color correctly unless it is selected. Then the legacy CellRenderer works as expected.

In my mind the Highlighter is at the view level and doesn't know about 'Object value'.

What would be ideal is if I could just add an interface tag to ANY OBJECT that is placed in the model and it knows how to renderer itself based on state.

So this method would become an Interface contract:

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)

Just refactor JTable above to be generic, and expose the 2D painter for setting the Pen Stroke attributes. foreground/background

Thoughts?

What is the suggested way I refactor legacy CellRenderers? I need to have something working by the end of the week.

Thanks,
Ed

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Kleopatra

Karl,

>>
>> I get locale specific formatters for things like
>> number and time delimiters. I only apply them in the
>> VIEW portion of the GUI.
>>
>> So for example..
>> Under the cover timestamps look like 000000. Based
>> on locale I change it to 00:00:00.
> I would say that you should use a special renderer to change the actual display text. That's the purpose of the renderer after all. And, for your example, the DateRenderer uses DateFormat internally, which is locale-bound. And, of course DateRenderer allows the formatter to be set as well.
>

Not exactly - no specific renderer (neither Date- nor Number- nor
whatever is formattable) needed. SwingX rendering support - internally
the ComponentProvider - has formatting support out-of-the box. All
that's needed is to feed a FormatStringValue with the formatter of your
choice and use it in the default.

[code]
Format format = DateFormat.getTimeInstance();
FormatStringValue sv = new FormatStringValue(myFormatter);
....setCellRenderer(new DefaultTableRenderer(sv);
[/code]

just added an custom time column to the Date-formatting example in
RendererVisualCheck.

(Sorry to disappoint you, Ed, but SwingX way of life is more comfortable
than you fear )

Cheers
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

Getting confused again.... ;-)

So the only area I can see where it 'might' make sense to CHANGE the TEXT in a CELL.

I have multiple clients using this in different locales. The guys in London wants date and time to look different than the guys in NYC.

I get locale specific formatters for things like number and time delimiters. I only apply them in the VIEW portion of the GUI.

So for example..
Under the cover timestamps look like 000000. Based on locale I change it to 00:00:00.

Always nice to have the option if you need it. ;-)

Cheers,
Ed

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> Getting confused again.... ;-)
>
> So the only area I can see where it 'might' make
> sense to CHANGE the TEXT in a CELL.
>
> I have multiple clients using this in different
> locales. The guys in London wants date and time to
> look different than the guys in NYC.
>
> I get locale specific formatters for things like
> number and time delimiters. I only apply them in the
> VIEW portion of the GUI.
>
> So for example..
> Under the cover timestamps look like 000000. Based
> on locale I change it to 00:00:00.
I would say that you should use a special renderer to change the actual display text. That's the purpose of the renderer after all. And, for your example, the DateRenderer uses DateFormat internally, which is locale-bound. And, of course DateRenderer allows the formatter to be set as well.

Karl

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

And to think this is Monday! :-)

I'm starting the day off on the right path. ;-)

Karl,

I'm currently using the legacy AcField TableCellRenderer to do just this for my Date and Time cells.

I was just afraid to tell you in fears you would peer pressure me into changing it. :-)

Cheers,
Ed

kschaefe
Offline
Joined: 2006-06-08
Points: 0

Ed,

You can do whatever you'd like to with your code. :)

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
>
> So should I tell my manager that the thing I finished last Friday still isn't DONE even though it works with no bugs???
>

well, QA might regard it as a bug to implement a predicate with a
side-effect ;-)

> I will try and refactor it AFTER you guys decide how it should work. ;-)
>
> I tried to get it done 'right' but I have to get it done 'right now'. :-)
>

maybe you should have followed the example more closely? Okay, the
tooltip via highlighter was commented at that time (because the reset
wasn't yet implemented) but ...

> Looks like you guys should write up a small wiki on how you want people to proceed.
>

people proceed like they want, whatever we write Feel free to update
the wiki in any way you feel might be helpful to others.

Anyway, I changed the SwingX renderering support default config to
always reset the tooltip to null, so now it is possible to implement a
Highlighter which decorates the tooltiptext property. And
updated/clarified (? being optimistic) the examples. A snippet for your
context:

[code]
HighlightPredicate acFieldPredicate = new .. {

boolean isHighlighted(...) {
return adapter.getValue() instanceof ACField &&
((ACField) adapter.getValue()).isSuspect();
}
}

Highlighter acToolTipHL = new AbstractHighlighter(acFieldPredicate)...{

void doHighlight(..) {
ACField field = ...;
component.setToolTipText(mapCodes.get(field.getStatus());
}
}

table.setHighlighters(
// ColorHighlighter with same color for un/selected foreground
new ColorHighlighter(null, Color.RED, null, Color.RED,
acFieldPredicate),
acToolTipHL);
[/code]

HTH
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Kleopatra

Karl,

>
> I have a small problem, however, with the work that the HighlightPredicate is doing (I'm a purist :). The area of concern for the predicate should be to determine whether the Highlighter should perform it's highlighting. I would not alter the renderer in any way while performing the predicate check. I would use something similar to my ToolTipHighlighter to alter the tool tips and then return an array of Highlighters, which can be passed into the setHighlighters(Highlighter...highlighters).
>

full ACK! And that's what one example in the visual check does ;-)

> Jeanette, why are we even passing the renderer into the predicate? I reviewed all of the predicates in the code base and none of them use the renderer. I really think we should change the HighlightPredicate's isHighlighted(Component, ComponentAdapter) to isHighlighted(ComponentAdapter).
>

Hmm ... I think that the predicate needs the same information as the
highlighter. Part of the argument is some trouble with the "old"
ConditionalHighlighter: for some use cases it was necessary to let the
test(ComponentAdapter) method return true always and do the actual
testing in a method which has the component as well. As now basically
this test method is separated into the predicate it got the component as
parameter to solve those cases. Maybe need to revisit ... but don't feel
much pressure to do it ;-)

In fact there is a (example) predicate that uses the component's text to
decide. Which may or may not be the right-thing-to-do (for now, it only
confused Ed ;-), future will tell.

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

Jeanette,

> > Jeanette, why are we even passing the renderer into
> the predicate? I reviewed all of the predicates in
> the code base and none of them use the renderer. I
> really think we should change the
> HighlightPredicate's isHighlighted(Component,
> ComponentAdapter) to isHighlighted(ComponentAdapter).
> >
>
> Hmm ... I think that the predicate needs the same
> information as the
> highlighter. Part of the argument is some trouble
> with the "old"
> ConditionalHighlighter: for some use cases it was
> necessary to let the
> test(ComponentAdapter) method return true always and
> do the actual
> testing in a method which has the component as well.
> As now basically
> this test method is separated into the predicate it
> got the component as
> parameter to solve those cases. Maybe need to revisit
> ... but don't feel
> much pressure to do it ;-)
I would argue that if we need the renderer to determine how to decorate it then we're missing information in the ComponentAdapter.

As I see it the Highlighter should be passed, a completely rendered renderer sans decorations. The Highlighter should be used to add decoration, such as background color, foreground color, possibly borders and tool tips. It should never change the rendered text. The HighlightPredicate should be in charge of determining whether or not a decoration should be displayed, but have no effect on rendering itself. This, I believe, only involves querying the ComponentAdapter. If the predicate is unable to determine something from the adapter, it probably falls into one of two cases, the user is attempting to alter something about the renderer in the predicate or the Adapter is likely missing functionality. Allowing the users to alter the renderer in the Predicate violates the seperation that we are trying to create and passing in the renderer enables that violation.

> In fact there is a (example) predicate that uses the
> component's text to
> decide. Which may or may not be the right-thing-to-do
> (for now, it only
> confused Ed ;-), future will tell.
(Sorry, Ed.) Which one? I looked at everything in the src, is it in the test area?

Kleopatra

Karl,

just to clarify: I'm not arguing in favor of predicates with
side-effects I'm arguing to give predicates as much flexibility for
their decision as they might need. Let's say, if my limited creativity
runs into contexts where I want to know the exact state of the exact
rendering component to base my decision upon, then I'm dead sure that
others will come crying for it are just round the corner.

The example is in HighlighterClientVisualCheck,
*ColorBasedOnComponentValue: the predicate decides based on the text of
the given label. Currently that is different from basing the decision on
the (if any and however created) string representation of the value.
Maybe it'll fall out, once we have a mechanism to create and share a
string-representation - as in

http://forums.java.net/jive/thread.jspa?threadID=21774&tstart=50

or maybe not. Simply don't know yet - we are here to find out

> (Sorry, Ed.) Which one? I looked at everything in the src, is it in the test area?

yeah, most of the small examples (*VisualCheck) are there - serving a
double purpose: show how-to do some things and have a place to look at
the visuals.

Thanks!
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

I spent about 10 minutes working on adding ComponentAdapter.getDisplayValue(), which returns a String. I created a protected method called getRenderingComponent(), which each class will implement. Currently, getDisplayValue does an instanceof/cast to JLabel to use getText().

It's quick and dirty and not yet in a state suitable for checkin, but I was able with little trouble to add the ability to obtain the display value. My timing tests also returned in 0 ms, meaning it's taking less than 1 ms to obtain the String representation. I have created a Predicate that highlighted !adapter.getDisplayValue().equals(adapter.getValue().toString()) and it paints as expected. All my Dates, Number greater than 1000, etc. show up highlighted.

My point here is that I think that we can really do a lot more in the Adapter. When I get a little more time, I'll get this into my incubator.

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
> I spent about 10 minutes

sprinter

> working on adding ComponentAdapter.getDisplayValue(), which returns a String. I created a protected method called getRenderingComponent(), which each class will implement. Currently, getDisplayValue does an instanceof/cast to JLabel to use getText().
>

might work (for getting a better hold on the one-string-for-all problem)
- but we should be very careful not to mimic the circular path as in
x/tree... (tree asks renderer asks tree, or in xTree: tree asks renderer
asks tree asks treeModel). As the adapter is a unified perspective onto
the view/model your suggestion is uncomfortably near to that. Doesn't
help if the predicate wants to decide based on other state of the
rendering component. For now, I'll leave the method as-is, and update
the doc that all params are to be considered strictly read-only.

>
> My point here is that I think that we can really do a lot more in the Adapter.

probably .. needs a overhaul anyway. But that will not happen as long as
it is serving two opposing masters ...

Thanks
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> jdnc-interest@javadesktop.org schrieb:
> > I spent about 10 minutes
>
>
> sprinter
That's usually you. Your the one to keep up with.

> > working on adding
> ComponentAdapter.getDisplayValue(), which returns a
> String. I created a protected method called
> getRenderingComponent(), which each class will
> implement. Currently, getDisplayValue does an
> instanceof/cast to JLabel to use getText().
> >
>
> might work (for getting a better hold on the
> one-string-for-all problem)
> - but we should be very careful not to mimic the
> circular path as in
> x/tree... (tree asks renderer asks tree, or in xTree:
> tree asks renderer
> asks tree asks treeModel). As the adapter is a
> unified perspective onto
> the view/model your suggestion is uncomfortably near
> to that. Doesn't
> help if the predicate wants to decide based on other
> state of the
> rendering component. For now, I'll leave the method
> as-is, and update
> the doc that all params are to be considered strictly
> read-only.
I spent a little time yesterday afternoon to get it workable from all renderer-capable SwingX components. I've committed the test code to src/kschaefe/renderer.

The real joy would be using the StringValue there, but the problem is the component may not actually display string data, such as Icons in the LabelProvider. So, we would need to duplicate the format code with some output. Did I ever mention that I don't like code duplication?

My current idea is not cyclic, it never talks back to the Component as JTree does, save that it gets another copy of the renderer. This is the only way that I could (quickly) figure out how to obtain ComponentProvider.format()ted data.

> > My point here is that I think that we can really do
> a lot more in the Adapter.
>
>
> probably .. needs a overhaul anyway. But that will
> not happen as long as
> it is serving two opposing masters ...
I started an in-depth reread of all of the decorator and renderer classes' JavaDocs today. So, I'm sure I'll have more comments later.

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
> I spent a little time yesterday afternoon to get it workable from all renderer-capable SwingX components. I've committed the test code to src/kschaefe/renderer.
>

cool - will look into it one of these days or so

> The real joy would be using the StringValue there, but the problem is the component may not actually display string data, such as Icons in the LabelProvider. So, we would need to duplicate the format code with some output. Did I ever mention that I don't like code duplication?
>

not that I remember you mentioning it

maybe we need a list of the most frequent things to content-format, it's
not that long ... String, Icon, (whatelse? tooltip? still not quite
convinced that it is merely decoration - but we'll see how it will be
used ;-) And then have a pluggable StringIconWhatEverValue.

> I started an in-depth reread of all of the decorator and renderer classes' JavaDocs today. So, I'm sure I'll have more comments later.
>

be sure to read the latest ... punished myself with doc writing today
(too much ... ehem ... beer yesterday :-)

Cheers
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> maybe we need a list of the most frequent things to
> content-format, it's
> not that long ... String, Icon, (whatelse? tooltip?
> still not quite
> convinced that it is merely decoration - but we'll
> see how it will be
> used ;-) And then have a pluggable
> StringIconWhatEverValue.
Sure, but that doesn't solve the problem. From LabelProvider:
[code]protected void format(CellContext context) {
if (context.getValue() instanceof Icon) {
rendererComponent.setIcon((Icon) context.getValue());
rendererComponent.setText(getStringValue(null));
} else {
rendererComponent.setIcon(null);
rendererComponent.setText(getStringValue(context));
}
}[/code]

If I build a custom provider, such as JustToIllustrateMyPointProvider extends LabelProvider with the following format method:
[code]protected void format(CellContext context) {
rendererComponent.setIcon(null);
rendererComponent.setText(getStringValue(context));
}[/code]
I removed the bifurcation of the code involving the Icon, so now I get a String representation of the Icon, which could be a URL to it's location, etc.

Without knowing exactly how the Provider is going to format (ie. actually use StringFormat, IconFormat, etc.), you're just applying formats willy-nilly to values. You cannot be assured that you are producing the exact same values as the renderer actually does.

Currently, we can only get at the output of format indirectly, via querying the Component returned by the Provider. How do we handle custom components? How do we establish a consistant API for accessing the rendered values? Perhaps ComponentProvider.getDisplayedValue() or some similar method.

That's just off the top of my head. I'm sure there are more devils in the details than the ones I've mentioned.

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
> Sure, but that doesn't solve the problem. From LabelProvider:
> [code]protected void format(CellContext context) {
> if (context.getValue() instanceof Icon) {
> rendererComponent.setIcon((Icon) context.getValue());
> rendererComponent.setText(getStringValue(null));
> } else {
> rendererComponent.setIcon(null);
> rendererComponent.setText(getStringValue(context));
> }
> }[/code]
>
> If I build a custom provider, such as JustToIllustrateMyPointProvider extends LabelProvider with the following format method:
> [code]protected void format(CellContext context) {
> rendererComponent.setIcon(null);
> rendererComponent.setText(getStringValue(context));
> }[/code]
> I removed the bifurcation of the code involving the Icon, so now I get a String representation of the Icon, which could be a URL to it's location, etc.
>

good point - and at last I got it . In fact, there are several
aspects, IMO (you mentioned much of it already, just to recap for myself):

- there is no guarantee that StringValue is respected by the provider's
format.

- StringValue is missing a getIcon, to allow a (icon-aware) provider to
respect it completely

- StringValue might not make sense for provider's to respect: f.i. a
checkbox provider is only interested in booleans, so it typically will
ignore the converter altogether. The implication is that we can't force
provider's by contract to respect it.

- ComponentProvider.getStringValue(context) is ... crap (besides the
fact that the renaming from formerly ToStringConverter to StringValue
was incomplete, must have forgotten to check the rename methods option
when doing it ;-): From the doc the (my) initial intent was to have it
as the hook to get the String Rep as shown on the rendering component,
from the implementation and usage, it's an internal method for the sake
of subclasses to get a safe (coping with null context) way to access the
value.

- going back to that initial intention: ComponentProvider is the
collaborator which really knows about how formatting may or may not
leads to a string rep in the rendering component. So it probably should
have a method to get at it from client code. This method would first
format and then return a concrete component specific aspect which maps
to the string rep.

There sure are more dirty details ahead , but this will get me
started to first cleanup the provider's internally used getString vs. a
hook for external usage ... This way, a provider can help a
componentAdapter to expose a displayValue (if we'll go that route) for
broader usage.

Cool discussion!

Thanks
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Kleopatra

Kleopatra schrieb:

to keep you posted (and mark this thread as [FYI] because it triggered a
more-than-minor change) - I opened an issue

https://swingx.dev.java.net/issues/show_bug.cgi?id=593

along the lines: XXProvider should respect the YYValues

for starters - XX was Label and YY was String.

Meanwhile I added

YY = Boolean
YY = Icon
YY = Mapped as a wrapper implementing all known YY and delegate

and let

XX = Label
XX = Button

respect it.

doohhh... probably not very clear? Maybe in a code snippet: the concrete
provider's format, f.i. LabelProvider

[code]
protected void format(CellContext) {
rendererComponent.setIcon(getValueAsIcon(context));
rendererComponent.setText(getValueAsString(context));
}

// in super
protected Icon getValueAsIcon(CellContext) {
if (formatter instanceof IconValue) {
return (IconValue) formatter.getIcon(context.getValue());
}
return null;
}
[/code]

Now the LabelProvider is fully configurable by client code (this is an
example from my incubator, FileTTNode is a node backed by the
FileSystemView, that is using the OS-specific icons):

[code]
StringValue converter = new StringValue() {

public String getString(Object value) {
if (value instanceof FileTTNode) {
FileTTNode file = (FileTTNode) value;
return file.getDisplayName();
}
return TO_STRING.getString(value);
}

};
IconValue iv = new IconValue() {

public Icon getIcon(Object value) {
if (value instanceof FileTTNode) {
FileTTNode file = (FileTTNode) value;
return file.getFileIcon();
}
return null;
}

};
// to show the FileTTNode in a table cell
TableCellRenderer r = new DefaultTableRenderer(
new MappedValue(sv, iv));
// re-use in tree
// create a wrappingProvider with the StringValue
// for use in the delegate provider used for the node content
WrappingProvider provider = new WrappingProvider(sv);
// set the IconValue for the provider itself
provider.setToStringConverter(new MappedValue(null, iv));
TreeCellRenderer treeR = new DefaultTreeRenderer(provider);
[/code]

What I really like with this approach is that it drastically reduced the
amount of provider subclasses: most examples which previously needed
subclassing could to use the base providers and configure with custom
converters (= XXValue).

Needs further cleanup, of course Apart from the naming ... what I'm
not so happy about is the way those converters are combined - I don't
want one big-for-all (getString, getIcon, getBoolean, getWhatever...),
but the "MappedV implements StringV, IconV, BooleanV,..." and set that
to the provider is fishy... ideas?

Okay, 'nough burbling, need to get some fresh air

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

kschaefe
Offline
Joined: 2006-06-08
Points: 0

> Trying to reach your goal with swingx
> provider/highlighter first showed
> that tooltips aren't supported out-off-the-box, that
> is setting them in
> the highlighter doesn't reset elsewhere - clearly an
> oversight - and
> exactly what I love to excersize the design.
>
> So the minimum support would be to reset in the
> provider - if we regard
> them as a visual decoration. Which I'm not really
> convinced they are.
> The alternative is to view them as part of the
> content, so the provider
> needs a (preferably pluggable, analogous to
> StringValue for the actual
> content) means to "format" the tooltip from the
> value. Any notion of
> conditional formatting currently is missing. The
> logic would be the same
> as in the Highlighter, sharing the predicate (as
> duplication is smelly)
> would be a way out - except it does take a
> ComponentAdapter while the
> provider uses a CellContext (very similar classes
> which should be merged
> anyway).
This may be the way that I use tool tips, but I always think of them as visual decorations. I would expect the same (or similar) mechanism to the Highlighters to accomplish tool tip decorations. They could be folded into the same mechanism or Highlighters extended to include tool tip decorations.

[code]public ToolTipHighlighter /*uggh, bad name*/ extends AbstractHighlighter {
private String toolTipText;

public ToolTipHighlighter(String toolTipText, HighlightPredicate predicate) {
super(predicate);
this.toolTipText = toolTipText;
}

protected Component doHighlight(Component renderer, ComponentAdapter adapter) {
//renderer must start the highlight chain without a tool tip
if (renderer instanceof JComponent) {
((JComponent) renderer).setToolTipText(toolTipText);
}

return renderer;
}
}[/code]

It would be nice to get an isTruncated() on the Adapter to allow users to easily display the entire cell contents when the cell is truncated.

Karl

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

I ended up just creating this static helper method in my applications JxTable class. I put everything here so if the user wants to change a global setting I just change it once. I don't like to type. ;-)

public static ColorHighlighter getAcFieldColorHighlighter()
{
HighlightPredicate predicate = new HighlightPredicate()
{
public boolean isHighlighted(Component renderer, ComponentAdapter adapter)
{
if (renderer instanceof JLabel)
{
JLabel label = (JLabel) renderer;
label.setToolTipText(null);
if (adapter.getValue() instanceof AcField)
{
AcField field = (AcField) adapter.getValue();
if (field.isSuspect())
{
renderer.setForeground(Color.RED);
String errorReason = MAP_CODES.get(new Integer(field.getStatus()));
label.setToolTipText(errorReason);
return true;
}
}
}
// default
return false;
} // end of isHighlighted()
};
return new ColorHighlighter(null, Color.RED, predicate);
}

When the tooltip is first created it acts a little strange. After that everything is fine. Works for me and I am running the swingx-2007_08_19.jar.

Thanks for everyone's feedback on this. I don't get deprecated compiler warnings now. :-)

Cheers,
Ed

kschaefe
Offline
Joined: 2006-06-08
Points: 0

Ed,

I'm glad that everything is working well (for the most part).

I have a small problem, however, with the work that the HighlightPredicate is doing (I'm a purist :). The area of concern for the predicate should be to determine whether the Highlighter should perform it's highlighting. I would not alter the renderer in any way while performing the predicate check. I would use something similar to my ToolTipHighlighter to alter the tool tips and then return an array of Highlighters, which can be passed into the setHighlighters(Highlighter...highlighters).

Jeanette, why are we even passing the renderer into the predicate? I reviewed all of the predicates in the code base and none of them use the renderer. I really think we should change the HighlightPredicate's isHighlighted(Component, ComponentAdapter) to isHighlighted(ComponentAdapter).

Karl

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

Karl,

You are cracking me up. :-)

So should I tell my manager that the thing I finished last Friday still isn't DONE even though it works with no bugs???

I will try and refactor it AFTER you guys decide how it should work. ;-)

I tried to get it done 'right' but I have to get it done 'right now'. :-)

Looks like you guys should write up a small wiki on how you want people to proceed.

Cheers,
Ed

kschaefe
Offline
Joined: 2006-06-08
Points: 0

Ed,

You've just brought to the fore some interesting use-cases. It will take a little time to explore, but in the end the refactor of our stuff (and then yours), if there is any, shouldn't be too difficult.

There are the current desgin notes in the [url=http://wiki.java.net/bin/view/Javadesktop/SwingLabsSwingX]wiki[/url].

Karl

kleopatra
Offline
Joined: 2003-06-11
Points: 0
cupofjoe
Offline
Joined: 2003-08-05
Points: 0

> JXTable and highlighters are MUCH quicker than the
> legacy way of doing this.

That sounded sarcastic. :-(

I meant to imply that the table paints itself and appears to be much smoother than the legacy JTable.

Just like me to try and give a compliment and it comes across as an insult. ;-)

Cheers,
Ed

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

Wow....

That was really painful. I need to move into Technical Sales or management. :-)

I used org.jdesktop.swingx.renderer.HighlighterVisualCheck
interactiveTableConditionalColorBasedOnValue() as my reference.

Jeanette please let me know if you see a gross sin in my implementation. I really do 'try' to keep learning and write clean code. :-)

So taking the TableRenderer example posted earlier I wrote a method that returns a Highlighter object. So adapter wraps the "Object value" legacy cell object and renderer is the 'rubber stamp' JLabel that I needed to set the tooltip against.

public ConditionalHighlighter getHighlighter()
{
ConditionalHighlighter highlighter = new ConditionalHighlighter()
{
@Override protected void applyForeground(Component [b]renderer[/b], ComponentAdapter [b]adapter[/b])
{
// default text to black
renderer.setForeground(Color.BLACK);
acFieldHighlight(renderer, adapter);
}

private void acFieldHighlight(Component renderer, ComponentAdapter adapter)
{
if (renderer instanceof JLabel)
{
JLabel label = (JLabel) renderer;
if (adapter.getValue() instanceof AcField)
{
AcField field = (AcField) adapter.getValue();
if (field.isSuspect())
{
renderer.setForeground(Color.RED);
label.setToolTipText(field.getFieldStatus().getDescription());
}
}
}
}

@Override public Component doHighlight(Component renderer, ComponentAdapter adapter)
{
if (adapter.isSelected())
{
// Do this here or it will NOT COLOR when selected correctly
acFieldHighlight(renderer, adapter);
return renderer;
}
return super.doHighlight(renderer, adapter);
}

/**
* HAVE TO DO THIS! Tagged as Abstract in parent.
*
* @param adapter ComponentAdapter
* @return boolean
*/
@Override protected boolean test(ComponentAdapter adapter)
{
return true;
}

};
return highlighter;
}

JXTable and highlighters are MUCH quicker than the legacy way of doing this.

Kind regards,
Ed

kschaefe
Offline
Joined: 2006-06-08
Points: 0

Ed,

ConditionalHighlighter is deprecated. You are using the old Highlighter setup. There was a Highlighter refactoring to seperate the paint from the predicates to make the painting code more reusable (and potentially the predicates as well).

The new style is to place the evaluation code into a HighlightPredicate, which determine whether the highlighter should paint. Most likely it would be something like:

[code]public class SuspectHighlightPredicate implements HighlightPredicate {
public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
Object value = adapter.getValue();

return value instanceof AcField && ((AcField) value).isSuspect();
}
}[/code]

And a ColorHighlighter:
[code]new ColorHighlighter(Color.RED, null, new SuspectHighlightPredicate());[/code]

This is off the top of my head and obviously untested, since it is based on your code that I do not have.

Karl

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

Thanks!

Kleopatra

Ed,

> I've been reading the threads on this since yesterday.
>

yeah - it takes some time, there are many ;-)

> It looked like someone was going to create a JX version of DefaultTableCellRenderer.
>

no, not exactly - the SwingX DefaultTableRenderer et al are just legacy
glue.

> I like the 'what' and 'how' seperation. I just can't seem to 'easily' get my objects to color correctly [u]unless[/u] it is selected. Then the legacy CellRenderer works as expected.
>

Typically, it's the other way round - problems without end when using
the core default renderer. So it's time for a small (!) runnable
example, please.

> In my mind the Highlighter is at the view level and doesn't know about 'Object value'.
>

agreed: it's view - and it's up to the view to decide about applying
visual decorations. If the decision is value/context based than it needs
a access to the relevant value/context state. In SwingX that decision is
factored into the HighlighterPredicate (not strictly, as Karl outlined -
the link is on the highlighter wiki page).

> What would be ideal is if I could just add an [b]interface [/b]tag to ANY OBJECT that is placed in the model and it knows how to renderer itself based on state.
>

no, I strongly disagree: the model is not the place to put
view-decisions. There must not be any link from the model to the view,
only the other way round is healthy.

>
> Just refactor JTable above to be generic, and expose the 2D painter for setting the Pen Stroke attributes. foreground/background
>

don't understand what you mean, sorry.

>
> What is the suggested way I refactor legacy CellRenderers?

move out the visual decorations into highlighters :-)

> I need to have something working by the end of the week.
>

you mean like "by today"? Good luck, my weekend starts soon.

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

> no, not exactly - the SwingX DefaultTableRenderer et
> al are just legacy
> glue.
There are many things that can only be done here. So if an Object in the CELL has just been created client side but not yet persisted to the DB you would render it GREEN. If you've tagged it for DELETE from the GUI but no yet submitted your client transaction to the server it would be RED.

The assumption that the VIEW can determine what to do based on a "String" will not work. The view HAS to delegate that to the OBJECT in the CELL or legacy Swing developers will never use JXTable IMHO.

Seriously, the current TableModel HAS methods that are ONLY for the view. ;-)
So for example:
public String getColumnName(int col)
public Class getColumnClass(final int col)

Please don't tell me your going to depricate getColumnClass because it tells the Table which renderer to use in the view. :-(

While I admire your attempt to 'fix' everything in Swing if you throw out Renderers most people I know are going to hack your code to keep them in. Every post I read on the topic ended with someone 'hacking' a renderer solution even if it meant giving up Highlighters.

Based on your current path I don't see any way for me to put another JComponent in the current cell. How would I do a CheckBox, ComboBox or custom component in a table cell without a renderer?

In some worlds of OO and UI design you delegate to the object since only IT knows how it should be rendered. This is exactly the concept of the entire JComponent painting framework right? The components are in a tree and the paint engine passes the 'paint brush' into each item based on alpha, opacity and clipping rules. Each Swing component paints itself and it has to set the 2D paint brush state back to normal or everyone gets the change. This is the common 'newbie' bug you get with Renderers as well. Forget to turn the color back to BLACK and wonder why after the first non-black cell every other cell is the new COLOR.

If every JComponent has a paintComponent() method than why is it such a stretch to create a generic dataModel that adds a paintOject() method?

If I had that I wouldn't need a renderer as long as paintObject can handle putting a component in a cell.

Time to hack a fix for a deadline. :-(

Thanks,
Ed

Kleopatra

Ed,

haha, looks like this is going to be another of our
talking-past-each-other debates ;-)

Your requirement with different colors based on some internal state is
quite easy to do in swingx - with highlighters. Please have a look at
the examples in the test hierarchy.

You are free to use jxtable or not, with or without swingx renderer
support. There is nothing that hinders you to keep your legacy renderers
- but you'll experience hard to solve issues with highlighters. Most
probably it'll boil down to either Highlighters or legacy renderers (if
you stick to the latter, be sure to turn off the
DefaultTableCellRenderer hack).

> Seriously, the current TableModel HAS methods that are ONLY for the view. ;-)
> So for example:
> public String getColumnName(int col)
> public Class getColumnClass(final int col)
>
> Please don't tell me your going to depricate getColumnClass because it tells the Table which renderer to use in the view. :-(

weeell ... no, I won't go as far as that Plus it's not necessarily
only the view that is interested in those. Having the notion of a column
type is quite usual. The name on the other hand is a ... design
accident, IMO: it should be an identifier instead. Caused quite some
corners to take in the glorious early days of this project, when the
table (data-) model had metaData attached. Which I still think was a
great idea.

> Based on your current path I don't see any way for me to put another JComponent in the current cell. How would I do a CheckBox, ComboBox or custom component in a table cell without a renderer?
>

not quite sure what do you mean by "put ... into the cell" -
interpreting it as using different/custom components as rendering
components for cell content, you'd implement a custom ComponentProvider.
The checkbox is available by default, the test hierarchy and my
incubator section have examples about others. Including Scott's xTreme
renderer for mail overviews - the nice thing being that it's one for all
types of collection views and highlighter-friendly out-off-the-box.

> In some worlds of OO and UI design you delegate to the object since only IT knows how it should be rendered.

yeah, that's an approach I heartily dislike. Makes them really
untestable and tends to mix concerns. So I'm quite happy that's not the
Swing/X way of life.

>
> Time to hack a fix for a deadline. :-(
>

If you show an example of what gives you problems, someone might come up
with some help ... just a hint :-)

Cheers
Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

I've seen several posts asking for details on how the Highlighter works.

I would rather catch my own fish but here is where I'm stuck:

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
AcField field = ((AcField) value);
if (field.isSuspect())
{
setForeground(Color.RED);
setToolTipText(field.getFieldStatus().getDescription());
}
else
{
// set text color to default
setForeground(Color.BLACK); // DEFAULT
}
}

The Highlighter changes in JXTable are causing the Red color to ghost in CELL (col-1,row+1) for ONLY one cell which seems odd.

I've been looking at the testing code for Highlighter and EVERYTHING works with TEXT in the Cell. I need to get to the underlying object.

Thanks,
Ed

Kleopatra

Ed,

hope you could update to a more recent version along the lines of Karl's
snippet :-)

Actually, your requirement got me really interested - as it needs a
value-based tooltip. First off:

>
> public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
> {
> AcField field = ((AcField) value);
> if (field.isSuspect())
> {
> setForeground(Color.RED);
> setToolTipText(field.getFieldStatus().getDescription());
> }
> else
> {
> // set text color to default
> setForeground(Color.BLACK); // DEFAULT
> }
> }
>

this renderer is not well behaved (or you don't show the whole code ;)
because it does not reset the tooltip in the else.

Trying to reach your goal with swingx provider/highlighter first showed
that tooltips aren't supported out-off-the-box, that is setting them in
the highlighter doesn't reset elsewhere - clearly an oversight - and
exactly what I love to excersize the design.

So the minimum support would be to reset in the provider - if we regard
them as a visual decoration. Which I'm not really convinced they are.
The alternative is to view them as part of the content, so the provider
needs a (preferably pluggable, analogous to StringValue for the actual
content) means to "format" the tooltip from the value. Any notion of
conditional formatting currently is missing. The logic would be the same
as in the Highlighter, sharing the predicate (as duplication is smelly)
would be a way out - except it does take a ComponentAdapter while the
provider uses a CellContext (very similar classes which should be merged
anyway).

Okay, it's Saturday - so no hard work today . I simply added (and
committed, now waiting that it doesn't blow anything) an example to the
HighlighterClientVisualCheck to show the possibilities.

Thanks for triggering a further step in the evolution!

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

cupofjoe
Offline
Joined: 2003-08-05
Points: 0

I fixed the tooltip last night. I was the only one still at my desk at 7PM. :-D

Thanks for thanking about my bug.

It is worth noting that setting the tooltip to NULL is the way to go. If you set it to "" and pay attention you will see a tiny box that looks like a flea following around the mouse cursor.

So the first thing I did was set the tooltip to NULL after the Renderer Label cast. Works like a charm.

I will upgrade to the latest on Monday.

Thanks!

Ed