This site is currently read-only as we are migrating to Oracle Forums for an improved community experience. You will not be able to initiate activity until January 31st, when you will be able to use this site as normal.

    Forum Stats

  • 3,890,899 Users
  • 2,269,649 Discussions
  • 7,916,821 Comments

Discussions

list widget with different colors for each list item?

RichF
RichF Member Posts: 214
edited Oct 15, 2010 11:37PM in Abstract Window Toolkit (AWT)
I'm going to add a list widget to my Interactive Color Wheel:

* http://r0k.us/graphics/SIHwheel.html

It's an old applet, first published in 1998, and pre-dating Swing.

The list will contain the 1,567 color names for which it knows color values. I would like to have the background color on each item to be that of its named color. The color name foreground text will be white or black, chosen for readability upon its background. Basically, I am hoping to accomplish what the Name that Color page does with its HTML-form list widget:

* http://chir.ag/projects/name-that-color/

I've studied the java.awt.list document:

* http://download.oracle.com/javase/1.4.2/docs/api/java/awt/List.html

The setBackground() and setForeground() methods are implemented, but they appear to only apply to the List as a whole. As far as I can tell, there appears to be no access to list items themselves as components. I hope I'm just missing the obvious.

-- Rich
Tagged:

Best Answer

  • pietblok
    pietblok Member Posts: 577
    Answer ✓
    What you want to do can be easyly implemented in a swing JList, with the help of a customized renderer. So I would advise to rewrite your applet in swing and then use a JList. That way you can skip studying JUnit just for forcing your awt applet to do something awt was nor designed for and concentrate on swing GUI stuff. Below an example of how you might implement your JList:
    import java.awt.*;
    import java.math.BigInteger;
    import java.util.Arrays;
    import java.util.Comparator;
    
    import javax.swing.*;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    
    public class ColorList {
    
        public static void main(String[] args) {
    	SwingUtilities.invokeLater(new Runnable() {
    
    	    @Override
    	    public void run() {
    		new ColorList().createGUI();
    	    }
    	});
        }
    
        private void createGUI() {
    	String[][] array = getArray();
    	// sort the array as you wish
    	Arrays.sort(array, new Comparator<String[]>() {
    
    	    @Override
    	    public int compare(String[] o1, String[] o2) {
    		return o1[1].compareTo(o2[1]);
    	    }
    
    	});
    	// create the JList
    	final JList list = new JList(array);
    	// set some adequate renderer
    	list.setCellRenderer(new DefaultListCellRenderer() {
    	    private static final long serialVersionUID = 1L;
    
    	    @Override
    	    public Component getListCellRendererComponent(JList list,
    		    Object value, int index, boolean isSelected,
    		    boolean cellHasFocus) {
    		DefaultListCellRenderer renderer = (DefaultListCellRenderer) super
    			.getListCellRendererComponent(list, value, index,
    				isSelected, cellHasFocus);
    		renderer.setText(((String[]) value)[1]);
    		int color = new BigInteger(((String[]) value)[0], 16)
    			.intValue();
    		renderer.setBackground(new Color(color));
    		renderer.setForeground(new Color(0xFFFFFFFF ^ color));
    		return renderer;
    	    }
    	});
    	final JLabel demoLabel = new JLabel(
    		"Display this text in the selected color", JLabel.CENTER);
    	list.addListSelectionListener(new ListSelectionListener() {
    
    	    @Override
    	    public void valueChanged(ListSelectionEvent e) {
    		String[] selected = (String[]) list.getSelectedValue();
    		demoLabel.setForeground(new Color(new BigInteger(selected[0],
    			16).intValue()));
    	    }
    	});
    
    	JFrame frame = new JFrame("ColorList");
    	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	frame.add(new JScrollPane(list), BorderLayout.LINE_START);
    	frame.add(demoLabel, BorderLayout.CENTER);
    	frame.pack();
    	frame.setLocationRelativeTo(null);
    	frame.setVisible(true);
        }
    
        private String[][] getArray() {
    	return new String[][] {
    
    	{ "000000", "Black" },
    
    	{ "000080", "Navy Blue" },
    
    	{ "0000C8", "Dark Blue" },
    
    	{ "0000FF", "Blue" },
    
    	{ "000741", "Stratos" },
    
    	{ "00FF00", "Green" },
    
    	{ "FF0000", "Red" },
    
    	{ "FFFFF0", "Ivory" },
    
    	{ "FFFFFF", "White" }
    
    	};
    
        }
    
    }
    Piet

Answers

  • RichF
    RichF Member Posts: 214
    Hmm, is the following telling me that setBackground(), although implemented for List.AccessibleAWTListChild, doesn't actually work?
    247:            public final void testSetBackground() {
    248:                Color color = Color.DARK_GRAY;
    249:                assertFalse(list.isBackgroundSet());
    250:                aComp3.setBackground(color);
    251:                assertEquals(color, aComp1.getBackground());
    252:                assertEquals(color, aComp2.getBackground());
    253:                assertEquals(color, aComp3.getBackground());
    254:                assertTrue("setBackground() is delegated to List", list
    255:                        .isBackgroundSet());
    256:                assertEquals(color, list.getBackground());
    257:            }
    above found at:

    * http://www.java2s.com/Open-Source/Java-Document/Apache-Harmony-Java-SE/java-package/java/awt/AccessibleAWTListChildTest.java.htm

    I have no knowledge of Java accessibility, but I was excited when I found something that gave access to "list children", such as aComp3 above. They seem to be the individual list items themselves. However, line 254 above seems to suggest something .. unfortunate. One may go through the motions of setting the background color of a child, but the setBackground() is actually delegated to the List as a whole. Am I interpreting this correctly?

    The above is part of a test suite implemented using:

    * import junit.framework.TestCase;

    I'm trying to avoid the learning curve to use JUnit when I already suspect the answer is "no". :(

    -- Rich
  • pietblok
    pietblok Member Posts: 577
    Answer ✓
    What you want to do can be easyly implemented in a swing JList, with the help of a customized renderer. So I would advise to rewrite your applet in swing and then use a JList. That way you can skip studying JUnit just for forcing your awt applet to do something awt was nor designed for and concentrate on swing GUI stuff. Below an example of how you might implement your JList:
    import java.awt.*;
    import java.math.BigInteger;
    import java.util.Arrays;
    import java.util.Comparator;
    
    import javax.swing.*;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    
    public class ColorList {
    
        public static void main(String[] args) {
    	SwingUtilities.invokeLater(new Runnable() {
    
    	    @Override
    	    public void run() {
    		new ColorList().createGUI();
    	    }
    	});
        }
    
        private void createGUI() {
    	String[][] array = getArray();
    	// sort the array as you wish
    	Arrays.sort(array, new Comparator<String[]>() {
    
    	    @Override
    	    public int compare(String[] o1, String[] o2) {
    		return o1[1].compareTo(o2[1]);
    	    }
    
    	});
    	// create the JList
    	final JList list = new JList(array);
    	// set some adequate renderer
    	list.setCellRenderer(new DefaultListCellRenderer() {
    	    private static final long serialVersionUID = 1L;
    
    	    @Override
    	    public Component getListCellRendererComponent(JList list,
    		    Object value, int index, boolean isSelected,
    		    boolean cellHasFocus) {
    		DefaultListCellRenderer renderer = (DefaultListCellRenderer) super
    			.getListCellRendererComponent(list, value, index,
    				isSelected, cellHasFocus);
    		renderer.setText(((String[]) value)[1]);
    		int color = new BigInteger(((String[]) value)[0], 16)
    			.intValue();
    		renderer.setBackground(new Color(color));
    		renderer.setForeground(new Color(0xFFFFFFFF ^ color));
    		return renderer;
    	    }
    	});
    	final JLabel demoLabel = new JLabel(
    		"Display this text in the selected color", JLabel.CENTER);
    	list.addListSelectionListener(new ListSelectionListener() {
    
    	    @Override
    	    public void valueChanged(ListSelectionEvent e) {
    		String[] selected = (String[]) list.getSelectedValue();
    		demoLabel.setForeground(new Color(new BigInteger(selected[0],
    			16).intValue()));
    	    }
    	});
    
    	JFrame frame = new JFrame("ColorList");
    	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	frame.add(new JScrollPane(list), BorderLayout.LINE_START);
    	frame.add(demoLabel, BorderLayout.CENTER);
    	frame.pack();
    	frame.setLocationRelativeTo(null);
    	frame.setVisible(true);
        }
    
        private String[][] getArray() {
    	return new String[][] {
    
    	{ "000000", "Black" },
    
    	{ "000080", "Navy Blue" },
    
    	{ "0000C8", "Dark Blue" },
    
    	{ "0000FF", "Blue" },
    
    	{ "000741", "Stratos" },
    
    	{ "00FF00", "Green" },
    
    	{ "FF0000", "Red" },
    
    	{ "FFFFF0", "Ivory" },
    
    	{ "FFFFFF", "White" }
    
    	};
    
        }
    
    }
    Piet
  • RichF
    RichF Member Posts: 214
    Piet, wow, that's beautiful!! :)

    What is amazing as the example you took time to write is that you pulled together info from two different threads in two different forums to do so. Thank you very much!

    Time to learn Swing, enter the 21st century ...

    -- Rich
  • User_64CKJ
    User_64CKJ Member Posts: 7,279 Silver Badge
    RichF wrote:
    Piet, wow, that's beautiful!! :)
    Agreed.
    ..Time to learn Swing, enter the 21st century ...
    ++ ;)
  • pietblok
    pietblok Member Posts: 577
    Andrew Thompson wrote:
    RichF wrote:
    Piet, wow, that's beautiful!! :)
    Agreed.
    ..Time to learn Swing, enter the 21st century ...
    ++ ;)
    So you see, in some cases, rare I do agree, just "giving the codes" may have some educational value ;-)
    Piet
  • RichF
    RichF Member Posts: 214
    Piet, converting to Swing will not only be educational, it will likely be easier than my other option. What I was considering was either extending awt.List, or perhaps rewriting it if necessary. I'm quite glad I don't have to reinvent the list...

    I posted an update to the other, "simpler way to sort 2-d string array?", thread:

    * 1557000

    Understated person which you are, you snuck in an answer to that question as well. Did you already know how to do that, or was the Javascript code I posted there an inspiration?

    One thing puzzles me in your example. Why the need for BigInteger? The hex color values are only 24-bit, which should not cause problems with 32-bit integers, right? Oh, I see. the Integer constructors do not include a form with radix, but the BigInteger constructors do. You've programmed with Java before. ;)

    -- Rich
  • pietblok
    pietblok Member Posts: 577
    RichF wrote:
    Understated person which you are, you snuck in an answer to that question as well. Did you already know how to do that, or was the Javascript code I posted there an inspiration?
    No. I usually skip all text that I don't understand. Javascript falls into that category. It's just the way I would do it.
    One thing puzzles me in your example. Why the need for BigInteger? The hex color values are only 24-bit, which should not cause problems with 32-bit integers, right? Oh, I see. the Integer constructors do not include a form with radix, but the BigInteger constructors do. You've programmed with Java before. ;)
    Here I was educated by kajbj, reply number 5 in this thread http://forums.sun.com/thread.jspa?threadID=5450453&tstart=90 on the old forums. I internalized that reply for the rest of my life.

    Piet
  • RichF
    RichF Member Posts: 214
    I've got the original awt code pretty-much ported to Swing now. The only new feature so far is that I've added toolTips to the GUI buttons. Neat!

    I say "pretty-much" because I haven't found an equivalent way to do the awt update() method. Under awt, I had overridden update() to handle the situation of a partial canvas update, such as only needing to update the wheel but not everything else. Since Swing never calls update() I'm patching it in by hand:
        // was named paint() in awt version
        public void paintComponent(Graphics g)
        {
            Rectangle ulc;
    
    	if (font == null)  defineFont(g);
    
    	// handle partial repaints of specific items
    	if (partialOnly(g))  return;
    
            if (r != null)
    	    r = null;	/*  re-init to handle resizing of frame  */
    	r = getBounds();
    
    	// for clean double-buffering
    	super.paintComponent(g);
    
            maxI = calcMaxI(intensity);
    
            g.setColor(background);
            g.fillRect(0, 0, r.width, r.height);
            ...
        }
    
        /**
        ***   There is no automatic update() with Swing.  Therefor we need
        *** to patch our own into paint to avoid complete redraws.
        **/
        public boolean partialOnly(Graphics g)
        {
    	boolean	imDone = true;
    
            if (wedgeOnly)
            {
    	    putDotOnWheel(g);
                paintWedge(g);
    	    drawSnake(g);
    	    drawSatSnake(g);
    	    updateLumaBars(g);
                wedgeOnly = false;
            }
              else if (wheelOnly)
              { // update the wedge's intensity dot and label
                putDotNearWedge(g);
    	    labelWedge(g);
    	    miscLabels(g);
    	    drawSnake(g);
    	    drawSatSnake(g);
                // update the GUI items having to do with intensity
                updateGUIintensity(g);
    	    updateLumaBars(g);
    
                paintWheel(g);
    	    putDotOnWheel(g);
                wheelOnly = false;
              }
              ... // etc
              else
                imDone = false;	// allow full paint()
    
    	return(imDone);
        }
    There are two problems; perhaps both relate to double-buffering. The first is that the canvas goes wonky-white when the user clicks on the wheel. What is supposed to happen is simply the user sees another dot on the wheel for his new selected color. Forcing a complete redraw via any of the GUI buttons at the bottom sets things right. The canvas behaves itself from then on, at least until minimized or resized, at which point one needs to click a GUI button again. I'll be disabling resizing, but minimizing will still be allowed.

    The second problem is that for some strange reason, the last selected GUI button and possibly it's tooltip will be replicated at the top of the painting canvas. Why this happens, I don't know -- they are two separate JPanels. Since a full paintComponent() refills the entire canvas, this effect was not visible until I started doing the partialOnly() stuff.

    You can see what the heck I'm talking about by downloading:

    * http://r0k.us/rock/Junk/SIHwheel.jar

    Type "java -jar SIHwheel.jar" to run it.

    What am I doing wrong?

    Heh, I hadn't run it as an applet until I checked on the html page in the Junk folder:

    * http://r0k.us/rock/Junk/SIHwheel.html

    It appears to function great as an applet, without either problem mentioned above.

    For anyone really interested, the full source is there as well:

    * http://r0k.us/rock/Junk/SIHwheel.java
    * http://r0k.us/rock/Junk/ntc.java

    (File ntc.java is only necessary if you plan on running it from your own build.)

    -- Rich
  • RichF
    RichF Member Posts: 214
    I have more or less fixed the first and most significant problem ("wonky-white"). I kludged-in two full paints:
        public boolean partialOnly(Graphics g)
        {
    	boolean	imDone = true;
    	if (resized > 0)
    	{   // should enter on 1 or 2
    	    imDone = false;
    	    resized += 1;	// clock thru two forced-full paints
    	    if (resized > 2)  resized = 0;
    	}
            ...
        }
    It is not elegant, but forcing the two full paints appears to do whatever magic the double-buffers need. I'm still looking for a non-kludgy solution, which I suspect will fix the second problem as well.
  • RichF
    RichF Member Posts: 214
    edited Oct 15, 2010 11:37PM
    I decided to continue this thread in the Swing forum. My issues are Swing now (yay!), and the other forum is a lot more popular. See "conversion from awt to Swing, colored list widget, and awt update() method" at:

    * 1685138

    Please respond there. Thank you.
This discussion has been closed.