Insubstantial / insubstantial

Swing look-and-feel library and assorted widgets
195 stars 57 forks source link

NPE at SubstanceColorUtilities.getInterpolatedRGB() #52

Closed cowwoc closed 12 years ago

cowwoc commented 12 years ago

I get this exception under Insubstance 7.0:


java.lang.NullPointerException
    at org.pushingpixels.substance.internal.utils.SubstanceColorUtilities.getInterpolatedRGB(SubstanceColorUtilities.java:154)
    at org.pushingpixels.substance.internal.utils.SubstanceColorUtilities.getInterpolatedColor(SubstanceColorUtilities.java:193)
    at org.pushingpixels.substance.internal.utils.SubstanceTextUtilities.getForegroundColor(SubstanceTextUtilities.java:382)
    at org.pushingpixels.substance.internal.utils.SubstanceTextUtilities.paintText(SubstanceTextUtilities.java:317)
    at org.pushingpixels.substance.internal.ui.SubstanceLabelUI.paint(SubstanceLabelUI.java:179)
    at org.pushingpixels.substance.internal.ui.SubstanceLabelUI.__org__pushingpixels__substance__internal__ui__SubstanceLabelUI__update(SubstanceLabelUI.java:198)
    at org.pushingpixels.substance.internal.ui.SubstanceLabelUI.update(SubstanceLabelUI.java)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.CellRendererPane.paintComponent(CellRendererPane.java:151)
    at javax.swing.plaf.basic.BasicListUI.paintCell(BasicListUI.java:227)
    at org.pushingpixels.substance.internal.ui.SubstanceListUI.paintCell(SubstanceListUI.java:579)
    at javax.swing.plaf.basic.BasicListUI.paintImpl(BasicListUI.java:317)
    at javax.swing.plaf.basic.BasicListUI.paint(BasicListUI.java:240)
    at org.pushingpixels.substance.internal.ui.SubstanceListUI.__org__pushingpixels__substance__internal__ui__SubstanceListUI__update(SubstanceListUI.java:788)
    at org.pushingpixels.substance.internal.ui.SubstanceListUI.update(SubstanceListUI.java)
    at javax.swing.JComponent.paintComponent(JComponent.java:778)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5228)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1482)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1413)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1206)
    at javax.swing.JComponent.paint(JComponent.java:1040)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)
    at java.awt.Container.paint(Container.java:1967)
    at java.awt.Window.paint(Window.java:3867)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:781)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:728)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677)
    at javax.swing.RepaintManager.access$700(RepaintManager.java:59)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1621)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:705)
    at java.awt.EventQueue.access$000(EventQueue.java:101)
    at java.awt.EventQueue$3.run(EventQueue.java:666)
    at java.awt.EventQueue$3.run(EventQueue.java:664)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:675)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

When changing the L&F to "Business". This is caused by a JList using the following ListCellRenderer:

public class JListTransparentCells extends DefaultListCellRenderer
{
    private static final long serialVersionUID = 1L;

    @Override
    public Color getBackground()
    {
        return null;
    }
}

A background color of null means that the background color of the parent component should be used (this works with the built-in L&Fs that ship with the JDK).

SubstanceTextUtilities.getForegroundColor() invokes SubstanceColorUtilities.getBackgroundFillColor(component) which returns null.

SubstanceColorUtilities.getInterpolatedColor() expects the second argument to be non-null but it doesn't actually check for it.

I recommend making the following changes:

  1. SubstanceColorUtilities.getBackgroundFillColor(component) should look at the parent if the component's background color is null.
  2. SubstanceColorUtilities.getInterpolatedColor() should check for a null argument and throw a clearer NullPointerException indicating that "color2" may not be null.
shemnon commented 12 years ago

It is the duty of the component to return the parent background color, not the painting subsystem to derive it. Here's some code from JComponent.java:

/**
 * Gets the background color of this component.
 * @return this component's background color; if this component does
 *          not have a background color,
 *          the background color of its parent is returned
 * @see #setBackground
 * @since JDK1.0
 */
public Color getBackground() {
    Color background = this.background;
    if (background != null) {
        return background;
    }
    Container parent = this.parent;
    return (parent != null) ? parent.getBackground() : null;
}

The default list cell renderer also has code to pull out the color of the JList in the getListCellRendererComponent method. There sounds like there is an entirely differnt problem you are attempting to solve via a hack with the background color, as this feels to me to be the wrong solution.

cowwoc commented 12 years ago

Shemnon,

Good catch! Thank you.