Skip to main content

AutoCompleteDecorator does not support nulls

19 replies [Last post]
tbee
Offline
Joined: 2003-07-23

AutoCompleteDecorator does not work correctly when a null is in the list. The example below illustrates this. If you run the class as-is, you are able to select the null value (rendered as "-").
If you then comment out the AutoCompleteDecorator part and rerun the class, the initial value is null, then select another and then try to reselect the "-". It won't work.

This is tested with 0.9.4 but I read a 0.9.5 thread with the same problem.

<br />
import java.awt.Component;</p>
<p>import javax.swing.DefaultListCellRenderer;<br />
import javax.swing.JComboBox;<br />
import javax.swing.JFrame;<br />
import javax.swing.JLabel;<br />
import javax.swing.JList;</p>
<p>import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;<br />
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;<br />
import org.tbee.swing.SwingUtilities;</p>
<p>public class AutoDecoratorTest<br />
{<br />
	public static void main(String[] args)<br />
	{<br />
		SwingUtilities.invokeLater(new Runnable()<br />
		{<br />
			@Override<br />
			public void run()<br />
			{<br />
				(new AutoDecoratorTest()).go();<br />
			}<br />
		});<br />
	}</p>
<p>	public void go()<br />
	{<br />
		JComboBox lJComboBox = new JComboBox(new String[]{null, "a", "b"});</p>
<p>		// set renderer<br />
		lJComboBox.setRenderer(new DefaultListCellRenderer()<br />
		{<br />
			public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)<br />
			{<br />
				// render<br />
				JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);<br />
				label.setText( value == null ? "-" : (String)value );<br />
				return label;<br />
			}<br />
		});		</p>
<p>		AutoCompleteDecorator.decorate(lJComboBox, new ObjectToStringConverter()<br />
		{<br />
			@Override<br />
			public String getPreferredStringForItem(Object item)<br />
			{<br />
				return (item == null ? "-" : (String)item);<br />
			}<br />
		});</p>
<p>		JFrame lJFrame = new JFrame();<br />
		lJFrame.add(lJComboBox);<br />
		lJFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );<br />
		lJFrame.pack();<br />
		lJFrame.setLocationRelativeTo(null);<br />
		lJFrame.setVisible(true);<br />
	}<br />
}<br />

Message was edited by: tbee

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tbee
Offline
Joined: 2003-07-23

> So far he himself, and, ah, Jonathan. But he is not
> taking the approach I would favor, so I'm not too
> jumpy about joining yet. Just refactoring generics in
> is not the way to go; I want issues like these taken
> out. More fundamental stuff.

Last side note on Swing2: other people usually know better how to put things into writing than me.

http://elliotth.blogspot.com/2009/02/swing-2-pissing-in-wind.html

markd_mms
Offline
Joined: 2009-03-25

Not sure if it helps you but I've made some changes to suit my purposes so the combobox can be editable and it can have a null selected item.

kleopatra
Offline
Joined: 2003-06-11

>
> @Null:
>
> You may be right that this is a conceptual problem.
> But JComboboxes (without autocompletion) work just
> fine

well, not exactly: your tweaked combo does :-) The core combo can't really cope with it - and that's perfectly valid, as the contract of ComboBoxModel .... bla bla.

>, and I believe that Java contains a lot of
> conceptual problems that people just live with.
> (Multithreaded instance variable access?)
>

Actually, I believe that this so-called conceptual problem is a bit home-brewn: by contract the null is used as a nothing-selected marker. This implies, that nulls in the list are undistinguishable from nothing selected, that is not really valid items. Ignoring the implication is .. well, done at one's own risk, as each contract violation.

What I'm against is to build upon too many tweaks. That's breaking right here (notwithstanding, that the maybe the autocomplete could tweaked as well so that it works with your tweaked combo which seems if we would be forced to follow the JIDE tweak which tweaks ... )

> However, the basis is this: there is this business
> model which gives me a list of enitities. And I have
> another entity with a property that can be assigned
> one of them or be null. So now I need to visualize
> that on screen.
>
> I most certainly am not going to make GUI specific
> changes to my business model.

nobody ever tried to push you into that direction - as I mentioned earlier, there are several possible solutions. Basically, the mapping from your business model to the ui-model (aka comboBoxModel) needs to be more clever.

>
> I'm practically focused: the JCombobox with null in
> its list works just fine, so the AutoCompletion could
> too. And for the "not selected" scenario we still
> have selected index == -1.
>

naturally, you are free to invent your own api Anyway, that's only loosely related to a ComboBoxModel (which doesn't have the notion of selected index, btw, so absolutely no way to resolve a not/-selected null)

Cheers
Jeanette

tbee
Offline
Joined: 2003-07-23

> would be forced to follow the JIDE tweak which tweaks...

You tweaked me out here... DoesNotComputeException, thank you very much :-)

But to use the male approach here: box works, man happy.

i30817
Offline
Joined: 2006-05-02

Have any objections to having a null object?
Can't you make any null object having equals return false, then any null object will not be ... oh toString() fuck.

Just realized null object requires turtles all the way down.

tbee
Offline
Joined: 2003-07-23

I have control over what goes in (the list of entities) and what comes out (the renderer), so if the box works correctly within those tight constraints -even though not 100% contract conform- I can live that that.

Now, I could of course write a utility method that creates a new instance of the list with any NULLs replaced with a special NULL object, and then on the other hand pull the selected value through a utility method that reverses that.
But since I use jGoodies binding, I would need to wrap that in the binding logic.

But bottom line is that IMHO the fact that JCombobox does not support null as valid items is evidence again that swing is not really thought through enough and this kind of behavior is exactly what makes the treshhold of for newcomers in using Swing so high. Another notch on Jonathan Giles' Swing 2.0 momentum.

kleopatra
Offline
Joined: 2003-06-11

> Now, I could of course write a utility method that
> creates a new instance of the list with any NULLs
> replaced with a special NULL object, and then on the
> other hand pull the selected value through a utility
> method that reverses that.
> But since I use jGoodies binding, I would need to
> wrap that in the binding logic.
>

that should be easy: insert a converter into the binding chain

> But bottom line is that IMHO the fact that JCombobox
> does not support null as valid items is evidence
> again that swing is not really thought through enough
> and this kind of behavior is exactly what makes the
> treshhold of for newcomers in using Swing so high.

No and yes:

No - the ComboBoxModel is the simplest way to support a single selected _item_ which need not necessarily be part of the list (that's why selected _index_ isn't good enough). It's a good abstraction for flexibility
Yes - using the same model for both contained and not-contained selection *and* at the same time interpret null as nothing-selected has implications which are not entirely clear at first sight, thus confusing (not-only :) newcomers

On the solution side: a ComboBoxModel with a special UNSELECTED object for denoting exactly that should do the trick, hmm

> Another notch on Jonathan Giles' Swing 2.0 momentum.

cool project but a gigantic task. Wondering who'll fund that?

Cheers
Jeanette

tbee
Offline
Joined: 2003-07-23

> that should be easy: insert a converter into the
> binding chain

Yes, but consider the "huh" code that comes to the binding line. I now have
- a wrapper in the chain to make sure the stuff is run inside the EDT
- a wrapper to catch IllegalArgumentExceptions and joptionpane those
And I would need a:
- wrapper to convert FAKENULL to NULL.

No one ever will understand that without a 5 day Swing course ;-)

> On the solution side: a ComboBoxModel with a special
> UNSELECTED object for denoting exactly that should do
> the trick, hmm

That is the second time you mention this... Maybe I should investigate that further?

> cool project but a gigantic task. Wondering who'll
> fund that?

So far he himself, and, ah, Jonathan. But he is not taking the approach I would favor, so I'm not too jumpy about joining yet. Just refactoring generics in is not the way to go; I want issues like these taken out. More fundamental stuff.

kleopatra
Offline
Joined: 2003-06-11

>
> > On the solution side: a ComboBoxModel with a
> special
> > UNSELECTED object for denoting exactly that should
> do
> > the trick, hmm
>
> That is the second time you mention this... Maybe I
> should investigate that further?
>

really only the _second_ time? feels like hundreds At least counting all my rants at different places over the years (gave up lately, SwingX gives me enough to rant about my own coding and api-design ;)

The JComboBox actually is a .. ehem ... suboptimal piece of work. Partly due to the not-good-enough model it grabs decisions it shouldn't deal with (like f.i. allowing only contained items if not-editable - not entirely sure if that's still an issue, but in the ol' days they didn't even show up). So suspect that any investigation will turn out rather frustrating, many places where that null == nothing-selected is exploited, some probably deep down in the plaf bowels. Naturally, would love to be wrong.

Cheers
Jeanette

tbee
Offline
Joined: 2003-07-23

> It seems JIDE autocomplete does work for nulls,
> although more complex to get working on the business
> model

Got the implemention JIDE running. It requires a custom editor and I need to do a scan-all-values in order to implement the getItem.

I see that the SwingX implementation does roughly the same internally, but for some reason the setItem correctly sets "-" to the editor, but getItem then gets the old value "a" from the editor, instead of "-".

tbee
Offline
Joined: 2003-07-23

@code tag: yes, I'm always searching for how to do that and then wonder why such a busy forum doesn't have them. Appearantly I do not post enough here to remember that it is supported... Or I'm showing first signs of dementia... Hm.

@Null:

You may be right that this is a conceptual problem. But JComboboxes (without autocompletion) work just fine, and I believe that Java contains a lot of conceptual problems that people just live with. (Multithreaded instance variable access?)

However, the basis is this: there is this business model which gives me a list of enitities. And I have another entity with a property that can be assigned one of them or be null. So now I need to visualize that on screen.

I most certainly am not going to make GUI specific changes to my business model. Then probably the webtier, SOA tier and EDIFACT tier will want to make similar changes (nasty buggers those tiers). So any shortcomings of the GUI tier must be handled in that tier to keep the API clean.

I'm practically focused: the JCombobox with null in its list works just fine, so the AutoCompletion could too. And for the "not selected" scenario we still have selected index == -1.

It seems JIDE autocomplete does work for nulls, although more complex to get working on the business model (haven't gotten there yet).

Message was edited by: tbee

kschaefe
Offline
Joined: 2006-06-08

You're going to have the problem of null and empty string collision. If the model contains both nulls and empty strings which one are you autocompleting? AutoComplete will choose the first match, always.

Karl

tbee
Offline
Joined: 2003-07-23

Yes. But the responsability of having a correct mapping of the null value to a string presentation (I usually use "-") is mine. I'm responsible for the content of the list and the renderer used by the jcombobox.

kleopatra
Offline
Joined: 2003-06-11

well, that mapping is ambigous if there are more than one nulls, right? Allowing nulls in the model is simply against-the-wind of its contract (though maybe not entirely violating it). Have a look at the model contract:

[code]
getSelectedItem

Object getSelectedItem()

Returns the selected item

Returns:
The selected item or null if there is no selection

[/code]

BTW.. have been there, that's where my personal rule comes from. In that case, I tend to ask myself: Why is there a need for a null? Would a NullObject (yeah, I know, some call it an anti-pattern, but sometimes they are handy) an option? Could the mapping be done in the presentation model layer?

HTH
Jeanette

PS: hey ... _you_ are along here for a while, so should remember how to format code Just in case: tag it with [ code ] ... [ /code ] markers (deleting the spaces in the tags) and complain to the forum site admin that those aren't documented anywhere.

kschaefe
Offline
Joined: 2006-06-08

> well, that mapping is ambigous if there are more than
> one nulls, right?

The selection is always ambiguous when a value appears twice. The first one is always selected. If you try a model with "a", "b", "c" repeated several times, the first a, b, or c is always selected regardless of which on you took. (That could be model-dependent, but the behavior exists.)

Karl

kleopatra
Offline
Joined: 2003-06-11

> > well, that mapping is ambigous if there are more
> than
> > one nulls, right?
>
> The selection is always ambiguous when a value
> appears twice.

caught me ... wrong argument, forgot to clarify that after adding the doc citation. Still stand by the contract violation: the api states that null == nothing selected. So if we have null items there is no way to distinguish nothing-selected from selected-null-item. Thanks for correcting!

Jeanette

kleopatra
Offline
Joined: 2003-06-11

Tom,

even without autoComplete, the "selection" of a null doesn't work completely in a JComboBox (to see, open the dropdown with the null selected - nothing selected in the list) Reason being that a selected item with value of null is interpreted as .. nothing selected, that is a conversion from selected item to selected index is bound to fail (return -1 always) My bottomline since ages: don't have null items in a comboBoxModel

Cheers
Jeanette

tbee
Offline
Joined: 2003-07-23

Ah, well, I my patched JComboBox has a patched getSelectedIndex method to handle null correctly. I did not include that to not make the example to complex, but one could replace the JComboBox with:

[code]
JComboBox lJComboBox = new JComboBox(new String[]{null, "a", "b"})
{
/**
* allow NULL as a possible selectable value
*/
public int getSelectedIndex()
{
Object sObject = dataModel.getSelectedItem();
int i,c;
Object obj;

for ( i=0,c=dataModel.getSize();i {
obj = dataModel.getElementAt(i);
if ( ObjectUtil.equals(obj, sObject) )
{
return i;
}
}
return -1;
}
};
[/code]
See? Null value neatly selected :-)

I simply have a need for null values. What would you use instead of null or JComboBox then?

Message was edited by: tbee

tbee
Offline
Joined: 2003-07-23

Hm, you also need this one:
[code]
static public boolean equals(Object o1, Object o2)
{
if ( o1 == null && o2 == null ) return true;
if ( o1 != null && o2 == null ) return false;
if ( o1 == null && o2 != null ) return false;
return o1.equals(o2);
}
[/code]