Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #20773 > unrolled thread

Generic JList and ListCellRenderer?

Started byKnute Johnson <nospam@knutejohnson.com>
First post2012-12-28 11:01 -0800
Last post2012-12-30 08:29 -0800
Articles 5 — 3 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Generic JList and ListCellRenderer? Knute Johnson <nospam@knutejohnson.com> - 2012-12-28 11:01 -0800
    Re: Generic JList and ListCellRenderer? "John B. Matthews" <nospam@nospam.invalid> - 2012-12-28 20:56 -0500
      Re: Generic JList and ListCellRenderer? Knute Johnson <nospam@knutejohnson.com> - 2012-12-30 08:27 -0800
    Re: Generic JList and ListCellRenderer? "Chris Uppal" <chris.uppal@metagnostic.REMOVE-THIS.org> - 2012-12-29 15:11 +0000
      Re: Generic JList and ListCellRenderer? Knute Johnson <nospam@knutejohnson.com> - 2012-12-30 08:29 -0800

#20773 — Generic JList and ListCellRenderer?

FromKnute Johnson <nospam@knutejohnson.com>
Date2012-12-28 11:01 -0800
SubjectGeneric JList and ListCellRenderer?
Message-ID<kbkqb6$uu3$1@dont-email.me>
I've been trying to clean up some really old code and I've hit some 
snags.  I've got several modified JLists and the ListCellRenderers for 
them and thought it would make sense to have generic classes that could 
be extended for different data types that need to be displayed.  The 
example below displays InetAddresses in the JList.  I've got another 
implementation of JList that does a lot more than what this one does but 
I wanted to keep this example simple and focus on the ListCellRenderer.

MyListCellRenderer extends the getListCellRenderer method of 
DefaultListCellRenderer and adds a new method, textToDisplay().  I added 
a field to the constructor that specifies the class of the data element 
to be displayed.  That class information is the test to make the call to 
the textToDisplay() method.  The InetAddressListCellRenderer class 
extends MyListCellRenderer to get this to display nice neat Strings for 
the InetAddresses.

I think this whole thing is a little kludgie.  I've been playing with it 
for so long now I'm not getting anywhere anymore.  I was hoping somebody 
would say "gee you ought to go this way" or "no that is really brilliant 
code my man!" and I'll leave it as is :-).

Anyway, please take a look and if you have any great ideas, I would 
appreciate the feedback.

Thanks,

import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;

public class test6 extends JPanel {
     public test6() throws UnknownHostException {
         Vector<InetAddress> v = new Vector<>();
         v.addElement(InetAddress.getByName("216.240.58.139"));
         v.addElement(InetAddress.getByName("4.2.2.1"));
         v.addElement(InetAddress.getByName("knutejohnson.com"));
         v.addElement(InetAddress.getByName("192.168.3.6"));

         MyJList<InetAddress> list =
          new MyJList<>(new DefaultListModel<InetAddress>());
         list.setCellRenderer(new InetAddressListCellRenderer());
         list.setListData(v);
         add(list);
     }

     public class MyJList<E> extends JList<E> {
         private final DefaultListModel<E> model;

         public MyJList(DefaultListModel<E> lm) {
             super(lm);
             this.model = lm;
         }

         public void setListData(E[] listData) {
             model.clear();
             for (E e : listData)
                 model.addElement(e);
         }

         public void setListData(Vector<? extends E> v) {
             model.clear();
             Iterator<? extends E> iter = v.iterator();
             while (iter.hasNext())
                 model.addElement(iter.next());
         }
     }

     public class MyListCellRenderer extends DefaultListCellRenderer {
         private final Class clazz;

         public MyListCellRenderer(Class clazz) {
             super();
             setOpaque(true);
             setBorder(new EmptyBorder(1,1,1,1));
             setName("List.cellRenderer");

             this.clazz = clazz;
         }

         public Component getListCellRendererComponent(JList<?> list,
          Object value, int index, boolean isSelected, boolean 
cellHasFocus) {
             setComponentOrientation(list.getComponentOrientation());

             UIDefaults defaults = UIManager.getDefaults();

             Color bg = null;
             Color fg = null;

             JList.DropLocation dropLocation = list.getDropLocation();
             if (dropLocation != null &&
               !dropLocation.isInsert() &&
               dropLocation.getIndex() == index) {
                 bg = (Color)defaults.get("List.dropCellBackground");
                 fg = (Color)defaults.get("List.dropCellForeground");

                 isSelected = true;
             }

             if (isSelected) {
                 setBackground(bg == null ? 
list.getSelectionBackground() : bg);
                 setForeground(fg == null ? 
list.getSelectionForeground() : fg);
             } else {
                 setBackground(list.getBackground());
                 setForeground(list.getForeground());
             }

             if (value instanceof Icon) {
                 setIcon((Icon)value);
                 setText("");
             } else if (clazz.isInstance(value)) {
                 setIcon(null);
//                setText(((InetAddress)value).getHostAddress());
                 setText(textToDisplay(value));
             /*
             } else {
                 setIcon(null);
                 setText((value == null) ? "" : value.toString());
             */
             }

             setEnabled(list.isEnabled());
             setFont(list.getFont());

             Border border = null;
             if (cellHasFocus) {
                 if (isSelected)
                     border = (Border)defaults.get(
                      "List.focusSelectedCellHighlightBorder");
                 if (border == null)
                     border = (Border)defaults.get(
                      "List.focusCellHighlightBorder");
             } else
                 border = new EmptyBorder(1,1,1,1);
             setBorder(border);

             return this;
         }

         public String textToDisplay(Object value) {
             return value == null ? "" : value.toString();
         }
     }

     public class InetAddressListCellRenderer extends MyListCellRenderer {
         public InetAddressListCellRenderer() {
             super(InetAddress.class);
         }

         public String textToDisplay(Object value) {
             return ((InetAddress)value).getHostAddress();
         }
     }

     public static void main(String[] args) {
         EventQueue.invokeLater(new Runnable() {
             public void run() {
                 try {
                     JFrame f = new JFrame();
                     f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                     test6 t6 = new test6();
                     f.add(t6);
                     f.pack();
                     f.setVisible(true);
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
         });
     }
}


-- 

Knute Johnson

[toc] | [next] | [standalone]


#20785

From"John B. Matthews" <nospam@nospam.invalid>
Date2012-12-28 20:56 -0500
Message-ID<nospam-49C732.20563528122012@news.aioe.org>
In reply to#20773
In article <kbkqb6$uu3$1@dont-email.me>,
 Knute Johnson <nospam@knutejohnson.com> wrote:

> I've been trying to clean up some really old code and I've hit some 
> snags.  I've got several modified JLists and the ListCellRenderers 
> for them and thought it would make sense to have generic classes that 
> could be extended for different data types that need to be displayed. 
>  The example below displays InetAddresses in the JList.  I've got 
> another implementation of JList that does a lot more than what this 
> one does but I wanted to keep this example simple and focus on the 
> ListCellRenderer.

Good use of a class literal as runtime type token:

<http://docs.oracle.com/javase/tutorial/extra/generics/literals.html>

> MyListCellRenderer extends the getListCellRenderer method of 
> DefaultListCellRenderer and adds a new method, textToDisplay().  I 
> added a field to the constructor that specifies the class of the data 
> element to be displayed.  That class information is the test to make 
> the call to the textToDisplay() method.  The 
> InetAddressListCellRenderer class extends MyListCellRenderer to get 
> this to display nice neat Strings for the InetAddresses.
> 
> I think this whole thing is a little kludgie.  I've been playing with 
> it for so long now I'm not getting anywhere anymore.  I was hoping 
> somebody would say "gee you ought to go this way" or "no that is 
> really brilliant code my man!" and I'll leave it as is :-).
> 
> Anyway, please take a look and if you have any great ideas, I would 
> appreciate the feedback.

Some suggestions:

Use the @Override annotation.

Use the for-each (Iterable) loop in setListData():

@Override
public void setListData(Vector<? extends E> v) {
    model.clear();
    for (E e : v) {
        model.addElement(e);
    }
}

Consider supporting List:

public void setListData(List<? extends E> v) {
    model.clear();
    for (E e : v) {
        model.addElement(e);
    }
}

Catch the more specific exception:

catch (UnknownHostException e)

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

[toc] | [prev] | [next] | [standalone]


#20820

FromKnute Johnson <nospam@knutejohnson.com>
Date2012-12-30 08:27 -0800
Message-ID<kbpq25$f1f$1@dont-email.me>
In reply to#20785
On 12/28/2012 5:56 PM, John B. Matthews wrote:
> In article <kbkqb6$uu3$1@dont-email.me>,
>   Knute Johnson <nospam@knutejohnson.com> wrote:
>
>> I've been trying to clean up some really old code and I've hit some
>> snags.  I've got several modified JLists and the ListCellRenderers
>> for them and thought it would make sense to have generic classes that
>> could be extended for different data types that need to be displayed.
>>   The example below displays InetAddresses in the JList.  I've got
>> another implementation of JList that does a lot more than what this
>> one does but I wanted to keep this example simple and focus on the
>> ListCellRenderer.
>
> Good use of a class literal as runtime type token:
>
> <http://docs.oracle.com/javase/tutorial/extra/generics/literals.html>
>
>> MyListCellRenderer extends the getListCellRenderer method of
>> DefaultListCellRenderer and adds a new method, textToDisplay().  I
>> added a field to the constructor that specifies the class of the data
>> element to be displayed.  That class information is the test to make
>> the call to the textToDisplay() method.  The
>> InetAddressListCellRenderer class extends MyListCellRenderer to get
>> this to display nice neat Strings for the InetAddresses.
>>
>> I think this whole thing is a little kludgie.  I've been playing with
>> it for so long now I'm not getting anywhere anymore.  I was hoping
>> somebody would say "gee you ought to go this way" or "no that is
>> really brilliant code my man!" and I'll leave it as is :-).
>>
>> Anyway, please take a look and if you have any great ideas, I would
>> appreciate the feedback.
>
> Some suggestions:
>
> Use the @Override annotation.
>
> Use the for-each (Iterable) loop in setListData():
>
> @Override
> public void setListData(Vector<? extends E> v) {
>      model.clear();
>      for (E e : v) {
>          model.addElement(e);
>      }
> }
>
> Consider supporting List:
>
> public void setListData(List<? extends E> v) {
>      model.clear();
>      for (E e : v) {
>          model.addElement(e);
>      }
> }
>
> Catch the more specific exception:
>
> catch (UnknownHostException e)
>

Thanks John.

-- 

Knute Johnson

[toc] | [prev] | [next] | [standalone]


#20801

From"Chris Uppal" <chris.uppal@metagnostic.REMOVE-THIS.org>
Date2012-12-29 15:11 +0000
Message-ID<rb6dnQdbEIzQlULNnZ2dnUVZ8oGdnZ2d@bt.com>
In reply to#20773
Knute Johnson wrote:

> I've been trying to clean up some really old code and I've hit some
> snags.  I've got several modified JLists and the ListCellRenderers for
> them and thought it would make sense to have generic classes that could
> be extended for different data types that need to be displayed.  The
> example below displays InetAddresses in the JList.  I've got another
> implementation of JList that does a lot more than what this one does but
> I wanted to keep this example simple and focus on the ListCellRenderer.

Without knowing what directions you intend/expect to extend the code it's a 
little difficult to make sensible suggestions.

So, proceeding with due absence of sense...

I don't see what the clazz variable (and the associated instance checks) are 
buying you.  You could try removing them and see if that makes your code come 
to life.  It would certainly remove some of the "kludgy" smell.

If that doesn't help, then it may be that you're being bothered by the way that 
ListCellRenderer has (so to speak) too many responsibilities -- it's 
simultaneously about /how/ something is displayed and about /what/ is 
displayed.

So (this is only my guess, of course) you're being pulled in two directions: on 
the one hand your /how/ is pretty much fixed and you want to use nice generic 
code for it whatever the types of the values, but the /what/ is not generic and 
will change according to each application.  You are being required to do 
rampant subclassing of something that shouldn't /need/ subclassing.

If that sounds as if it might relate to your problem, you could introduce a new 
kind of object who's only responsibility is to take a value, the element of the 
List (of type Object -- unless you want to mess with generics), and return a 
String which is to be the contents of the cell.  It might also have a parallel 
method which takes the (same) List element and returns an Icon (or null).

The new object would have appropriate subclasses for InetAddress etc.  (which 
might or might not appear formally as separate classes in your source -- you 
could instead use anonymous classes to make the getTextFor() and getIconFor() 
methods "pluggable").

So then you have just one subclass of ListCellRenderer which holds an instance 
of [a subclass of] this new class (instead of the clazz variable), and which 
always blindly uses that to "fetch" the appropriate String and/or Icon for use 
for each cell.

It's difficult to think of a good name for the new kind of object (and it's 
subclasses), but in this case I don't think that's the danger sign it normally 
would be: the reason that it's difficult to find a name is that the obvious 
names (some variant on "Renderer") are already taken.  "TextSupplier" perhaps 
(or ContentSupplier, or ContentTranslator) ?

It could well be that this kind of picture is over-engineered for your purposes 
(I can't tell).  But even if it is, then the real culprit is the Swing 
architecture which is under-engineered (here), so something may be needed to 
compensate.

    -- chris 

[toc] | [prev] | [next] | [standalone]


#20821

FromKnute Johnson <nospam@knutejohnson.com>
Date2012-12-30 08:29 -0800
Message-ID<kbpq52$f1f$2@dont-email.me>
In reply to#20801
On 12/29/2012 7:11 AM, Chris Uppal wrote:
> Knute Johnson wrote:
>
>> I've been trying to clean up some really old code and I've hit some
>> snags.  I've got several modified JLists and the ListCellRenderers for
>> them and thought it would make sense to have generic classes that could
>> be extended for different data types that need to be displayed.  The
>> example below displays InetAddresses in the JList.  I've got another
>> implementation of JList that does a lot more than what this one does but
>> I wanted to keep this example simple and focus on the ListCellRenderer.
>
> Without knowing what directions you intend/expect to extend the code it's a
> little difficult to make sensible suggestions.
>
> So, proceeding with due absence of sense...
>
> I don't see what the clazz variable (and the associated instance checks) are
> buying you.  You could try removing them and see if that makes your code come
> to life.  It would certainly remove some of the "kludgy" smell.
>
> If that doesn't help, then it may be that you're being bothered by the way that
> ListCellRenderer has (so to speak) too many responsibilities -- it's
> simultaneously about /how/ something is displayed and about /what/ is
> displayed.
>
> So (this is only my guess, of course) you're being pulled in two directions: on
> the one hand your /how/ is pretty much fixed and you want to use nice generic
> code for it whatever the types of the values, but the /what/ is not generic and
> will change according to each application.  You are being required to do
> rampant subclassing of something that shouldn't /need/ subclassing.
>
> If that sounds as if it might relate to your problem, you could introduce a new
> kind of object who's only responsibility is to take a value, the element of the
> List (of type Object -- unless you want to mess with generics), and return a
> String which is to be the contents of the cell.  It might also have a parallel
> method which takes the (same) List element and returns an Icon (or null).
>
> The new object would have appropriate subclasses for InetAddress etc.  (which
> might or might not appear formally as separate classes in your source -- you
> could instead use anonymous classes to make the getTextFor() and getIconFor()
> methods "pluggable").
>
> So then you have just one subclass of ListCellRenderer which holds an instance
> of [a subclass of] this new class (instead of the clazz variable), and which
> always blindly uses that to "fetch" the appropriate String and/or Icon for use
> for each cell.
>
> It's difficult to think of a good name for the new kind of object (and it's
> subclasses), but in this case I don't think that's the danger sign it normally
> would be: the reason that it's difficult to find a name is that the obvious
> names (some variant on "Renderer") are already taken.  "TextSupplier" perhaps
> (or ContentSupplier, or ContentTranslator) ?
>
> It could well be that this kind of picture is over-engineered for your purposes
> (I can't tell).  But even if it is, then the real culprit is the Swing
> architecture which is under-engineered (here), so something may be needed to
> compensate.
>
>      -- chris
>
>

Thanks Chris.

-- 

Knute Johnson

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web