Java中的fillArc()没有按预期混合颜色

时间:2015-09-28 01:33:22

标签: java graphics drawing

我尝试使用弧线将所有颜色混合成一个圆圈。 然而,弧线是一种纯色而不是我想的颜色混合。 有可能吗?

 public static void main(String[] args) {
    DrawingPanel panel = new DrawingPanel(512,512);
    Graphics g = panel.getGraphics(); 

    int width = 100; 
    int height = 100; 

        g.drawOval(0,0,width, height);
        //yellow
        for( int i = 0; i < 100 ; i++){ 
            Color c = new Color(255/100*i,255,0);
            g.setColor(c);
            g.fillArc(0,0,width,height,95,11);
        }

2 个答案:

答案 0 :(得分:1)

g.fillArc(0,0,width,height,95,11);

您需要更改每次迭代的弧角,并且弧的大小应固定为某个值。我不确定这个值会是什么,因为我希望你应该迭代360次(在这种情况下,大小将是1),而不是100。

您可以使用HSL Color类来完成此操作。

enter image description here

HSL颜色允许您以度为单位更改颜色的“色调”。所以你只需要一个简单的循环来设置/绘制1度弧的颜色:

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;

public class ColorWheel extends JPanel
{
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        HSLColor color = new HSLColor( Color.YELLOW );

        for (int i = 0; i < 360; i++)
        {
            g.setColor( color.adjustHue(i) );
            g.fillArc( 25, 25, 200, 200, i, 1);
        }
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(250, 250);
    }

    private static void createAndShowGUI()
    {
        JComponent wheel = new ColorWheel();

        JFrame frame = new JFrame("Color Wheel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane( wheel );
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

我使用HSL Color,因为它有一个简单的API来更改色调。

如果您不想使用该类,则可以使用Color.getHSBColor(...)方法获取每个更改程度的颜色。饱和度和亮度再次是固定值,然后您只需更改色调。

@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);

    float hueDegree = 1 / 360.0f;

    for (int i = 0; i < 360; i++)
    {
        Color color = Color.getHSBColor(i * hueDegree, 1.0f, 1.0f);
        g.setColor( color );
        g.fillArc( 25, 25, 200, 200, i, 1);
    }
}

答案 1 :(得分:0)

前段时间,我偶然发现了来自Harmonic Code public class Game { public GameState State { get; set; } public Board Board { get; set; } public IEnumerable<Player> Players { get; set; } public bool Move(int playerId, int field) { //Check if Player's move will finish game. If yes, return true return false; } } 的{​​{1}}(某处有来源,我似乎无法再找到它,但我已经包括了我的在示例中复制它。

enter image description here

ConicalGradientPaint

要尝试使用饼图片做你正在做的事情,你需要使用非常小的片段慢慢地将颜色从一个点改变到另一个点。因此,虽然您可以从import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class ColorWheel { public static void main(String[] args) { new ColorWheel(); } public ColorWheel() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); ConicalGradientPaint rgp = new ConicalGradientPaint( true, new Point(getWidth() / 2, getHeight() / 2), 0.5f, new float[]{0, 60, 120, 180, 240, 300, 360}, new Color[]{Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.RED}); g2d.setPaint(rgp); int radius = Math.min(getWidth(), getHeight()); int x = (getWidth() - radius) / 2; int y = (getHeight() - radius) / 2; g2d.fillOval(x, y, radius, radius); g2d.dispose(); } } public final class ConicalGradientPaint implements java.awt.Paint { private final java.awt.geom.Point2D CENTER; private final double[] FRACTION_ANGLES; private final double[] RED_STEP_LOOKUP; private final double[] GREEN_STEP_LOOKUP; private final double[] BLUE_STEP_LOOKUP; private final double[] ALPHA_STEP_LOOKUP; private final java.awt.Color[] COLORS; private static final float INT_TO_FLOAT_CONST = 1f / 255f; /** * Standard constructor which takes the FRACTIONS in values from 0.0f to * 1.0f * * @param CENTER * @param GIVEN_FRACTIONS * @param GIVEN_COLORS * @throws IllegalArgumentException */ public ConicalGradientPaint(final java.awt.geom.Point2D CENTER, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException { this(false, CENTER, 0.0f, GIVEN_FRACTIONS, GIVEN_COLORS); } /** * Enhanced constructor which takes the FRACTIONS in degress from 0.0f to * 360.0f and also an GIVEN_OFFSET in degrees around the rotation CENTER * * @param USE_DEGREES * @param CENTER * @param GIVEN_OFFSET * @param GIVEN_FRACTIONS * @param GIVEN_COLORS * @throws IllegalArgumentException */ public ConicalGradientPaint(final boolean USE_DEGREES, final java.awt.geom.Point2D CENTER, final float GIVEN_OFFSET, final float[] GIVEN_FRACTIONS, final java.awt.Color[] GIVEN_COLORS) throws IllegalArgumentException { // Check that fractions and colors are of the same size if (GIVEN_FRACTIONS.length != GIVEN_COLORS.length) { throw new IllegalArgumentException("Fractions and colors must be equal in size"); } final java.util.ArrayList<Float> FRACTION_LIST = new java.util.ArrayList<Float>(GIVEN_FRACTIONS.length); final float OFFSET; if (USE_DEGREES) { final double DEG_FRACTION = 1f / 360f; if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), -0.5) == 0) { OFFSET = -0.5f; } else if (Double.compare((GIVEN_OFFSET * DEG_FRACTION), 0.5) == 0) { OFFSET = 0.5f; } else { OFFSET = (float) (GIVEN_OFFSET * DEG_FRACTION); } for (float fraction : GIVEN_FRACTIONS) { FRACTION_LIST.add((float) (fraction * DEG_FRACTION)); } } else { // Now it seems to work with rotation of 0.5f, below is the old code to correct the problem // if (GIVEN_OFFSET == -0.5) // { // // This is needed because of problems in the creation of the Raster // // with a angle offset of exactly -0.5 // OFFSET = -0.49999f; // } // else if (GIVEN_OFFSET == 0.5) // { // // This is needed because of problems in the creation of the Raster // // with a angle offset of exactly +0.5 // OFFSET = 0.499999f; // } // else { OFFSET = GIVEN_OFFSET; } for (float fraction : GIVEN_FRACTIONS) { FRACTION_LIST.add(fraction); } } // Check for valid offset if (OFFSET > 0.5f || OFFSET < -0.5f) { throw new IllegalArgumentException("Offset has to be in the range of -0.5 to 0.5"); } // Adjust fractions and colors array in the case where startvalue != 0.0f and/or endvalue != 1.0f final java.util.List<java.awt.Color> COLOR_LIST = new java.util.ArrayList<java.awt.Color>(GIVEN_COLORS.length); COLOR_LIST.addAll(java.util.Arrays.asList(GIVEN_COLORS)); // Assure that fractions start with 0.0f if (FRACTION_LIST.get(0) != 0.0f) { FRACTION_LIST.add(0, 0.0f); final java.awt.Color TMP_COLOR = COLOR_LIST.get(0); COLOR_LIST.add(0, TMP_COLOR); } // Assure that fractions end with 1.0f if (FRACTION_LIST.get(FRACTION_LIST.size() - 1) != 1.0f) { FRACTION_LIST.add(1.0f); COLOR_LIST.add(GIVEN_COLORS[0]); } // Recalculate the fractions and colors with the given offset final java.util.Map<Float, java.awt.Color> FRACTION_COLORS = recalculate(FRACTION_LIST, COLOR_LIST, OFFSET); // Clear the original FRACTION_LIST and COLOR_LIST FRACTION_LIST.clear(); COLOR_LIST.clear(); // Sort the hashmap by fraction and add the values to the FRACION_LIST and COLOR_LIST final java.util.SortedSet<Float> SORTED_FRACTIONS = new java.util.TreeSet<Float>(FRACTION_COLORS.keySet()); final java.util.Iterator<Float> ITERATOR = SORTED_FRACTIONS.iterator(); while (ITERATOR.hasNext()) { final float CURRENT_FRACTION = ITERATOR.next(); FRACTION_LIST.add(CURRENT_FRACTION); COLOR_LIST.add(FRACTION_COLORS.get(CURRENT_FRACTION)); } // Set the values this.CENTER = CENTER; COLORS = COLOR_LIST.toArray(new java.awt.Color[]{}); // Prepare lookup table for the angles of each fraction final int MAX_FRACTIONS = FRACTION_LIST.size(); this.FRACTION_ANGLES = new double[MAX_FRACTIONS]; for (int i = 0; i < MAX_FRACTIONS; i++) { FRACTION_ANGLES[i] = FRACTION_LIST.get(i) * 360; } // Prepare lookup tables for the color stepsize of each color RED_STEP_LOOKUP = new double[COLORS.length]; GREEN_STEP_LOOKUP = new double[COLORS.length]; BLUE_STEP_LOOKUP = new double[COLORS.length]; ALPHA_STEP_LOOKUP = new double[COLORS.length]; for (int i = 0; i < (COLORS.length - 1); i++) { RED_STEP_LOOKUP[i] = ((COLORS[i + 1].getRed() - COLORS[i].getRed()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); GREEN_STEP_LOOKUP[i] = ((COLORS[i + 1].getGreen() - COLORS[i].getGreen()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); BLUE_STEP_LOOKUP[i] = ((COLORS[i + 1].getBlue() - COLORS[i].getBlue()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); ALPHA_STEP_LOOKUP[i] = ((COLORS[i + 1].getAlpha() - COLORS[i].getAlpha()) * INT_TO_FLOAT_CONST) / (FRACTION_ANGLES[i + 1] - FRACTION_ANGLES[i]); } } /** * Recalculates the fractions in the FRACTION_LIST and their associated * colors in the COLOR_LIST with a given OFFSET. Because the conical * gradients always starts with 0 at the top and clockwise direction you * could rotate the defined conical gradient from -180 to 180 degrees which * equals values from -0.5 to +0.5 * * @param FRACTION_LIST * @param COLOR_LIST * @param OFFSET * @return Hashmap that contains the recalculated fractions and colors after * a given rotation */ private java.util.HashMap<Float, java.awt.Color> recalculate(final java.util.List<Float> FRACTION_LIST, final java.util.List<java.awt.Color> COLOR_LIST, final float OFFSET) { // Recalculate the fractions and colors with the given offset final int MAX_FRACTIONS = FRACTION_LIST.size(); final java.util.HashMap<Float, java.awt.Color> FRACTION_COLORS = new java.util.HashMap<Float, java.awt.Color>(MAX_FRACTIONS); for (int i = 0; i < MAX_FRACTIONS; i++) { // Add offset to fraction final float TMP_FRACTION = FRACTION_LIST.get(i) + OFFSET; // Color related to current fraction final java.awt.Color TMP_COLOR = COLOR_LIST.get(i); // Check each fraction for limits (0...1) if (TMP_FRACTION <= 0) { FRACTION_COLORS.put(1.0f + TMP_FRACTION + 0.0001f, TMP_COLOR); final float NEXT_FRACTION; final java.awt.Color NEXT_COLOR; if (i < MAX_FRACTIONS - 1) { NEXT_FRACTION = FRACTION_LIST.get(i + 1) + OFFSET; NEXT_COLOR = COLOR_LIST.get(i + 1); } else { NEXT_FRACTION = 1 - FRACTION_LIST.get(0) + OFFSET; NEXT_COLOR = COLOR_LIST.get(0); } if (NEXT_FRACTION > 0) { final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, NEXT_COLOR, (int) ((NEXT_FRACTION - TMP_FRACTION) * 10000), (int) ((-TMP_FRACTION) * 10000)); FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR); FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR); } } else if (TMP_FRACTION >= 1) { FRACTION_COLORS.put(TMP_FRACTION - 1.0f - 0.0001f, TMP_COLOR); final float PREVIOUS_FRACTION; final java.awt.Color PREVIOUS_COLOR; if (i > 0) { PREVIOUS_FRACTION = FRACTION_LIST.get(i - 1) + OFFSET; PREVIOUS_COLOR = COLOR_LIST.get(i - 1); } else { PREVIOUS_FRACTION = FRACTION_LIST.get(MAX_FRACTIONS - 1) + OFFSET; PREVIOUS_COLOR = COLOR_LIST.get(MAX_FRACTIONS - 1); } if (PREVIOUS_FRACTION < 1) { final java.awt.Color NEW_FRACTION_COLOR = getColorFromFraction(TMP_COLOR, PREVIOUS_COLOR, (int) ((TMP_FRACTION - PREVIOUS_FRACTION) * 10000), (int) (TMP_FRACTION - 1.0f) * 10000); FRACTION_COLORS.put(1.0f, NEW_FRACTION_COLOR); FRACTION_COLORS.put(0.0f, NEW_FRACTION_COLOR); } } else { FRACTION_COLORS.put(TMP_FRACTION, TMP_COLOR); } } // Clear the original FRACTION_LIST and COLOR_LIST FRACTION_LIST.clear(); COLOR_LIST.clear(); return FRACTION_COLORS; } /** * With the START_COLOR at the beginning and the DESTINATION_COLOR at the * end of the given RANGE the method will calculate and return the color * that equals the given VALUE. e.g. a START_COLOR of BLACK (R:0, G:0, B:0, * A:255) and a DESTINATION_COLOR of WHITE(R:255, G:255, B:255, A:255) with * a given RANGE of 100 and a given VALUE of 50 will return the color that * is exactly in the middle of the gradient between black and white which is * gray(R:128, G:128, B:128, A:255) So this method is really useful to * calculate colors in gradients between two given colors. * * @param START_COLOR * @param DESTINATION_COLOR * @param RANGE * @param VALUE * @return Color calculated from a range of values by given value */ public java.awt.Color getColorFromFraction(final java.awt.Color START_COLOR, final java.awt.Color DESTINATION_COLOR, final int RANGE, final int VALUE) { final float SOURCE_RED = START_COLOR.getRed() * INT_TO_FLOAT_CONST; final float SOURCE_GREEN = START_COLOR.getGreen() * INT_TO_FLOAT_CONST; final float SOURCE_BLUE = START_COLOR.getBlue() * INT_TO_FLOAT_CONST; final float SOURCE_ALPHA = START_COLOR.getAlpha() * INT_TO_FLOAT_CONST; final float DESTINATION_RED = DESTINATION_COLOR.getRed() * INT_TO_FLOAT_CONST; final float DESTINATION_GREEN = DESTINATION_COLOR.getGreen() * INT_TO_FLOAT_CONST; final float DESTINATION_BLUE = DESTINATION_COLOR.getBlue() * INT_TO_FLOAT_CONST; final float DESTINATION_ALPHA = DESTINATION_COLOR.getAlpha() * INT_TO_FLOAT_CONST; final float RED_DELTA = DESTINATION_RED - SOURCE_RED; final float GREEN_DELTA = DESTINATION_GREEN - SOURCE_GREEN; final float BLUE_DELTA = DESTINATION_BLUE - SOURCE_BLUE; final float ALPHA_DELTA = DESTINATION_ALPHA - SOURCE_ALPHA; final float RED_FRACTION = RED_DELTA / RANGE; final float GREEN_FRACTION = GREEN_DELTA / RANGE; final float BLUE_FRACTION = BLUE_DELTA / RANGE; final float ALPHA_FRACTION = ALPHA_DELTA / RANGE; //System.out.println(DISTANCE + " " + CURRENT_FRACTION); return new java.awt.Color(SOURCE_RED + RED_FRACTION * VALUE, SOURCE_GREEN + GREEN_FRACTION * VALUE, SOURCE_BLUE + BLUE_FRACTION * VALUE, SOURCE_ALPHA + ALPHA_FRACTION * VALUE); } @Override public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, final java.awt.geom.Rectangle2D USER_BOUNDS, final java.awt.geom.AffineTransform TRANSFORM, final java.awt.RenderingHints HINTS) { final java.awt.geom.Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null); return new ConicalGradientPaintContext(TRANSFORMED_CENTER); } @Override public int getTransparency() { return java.awt.Transparency.TRANSLUCENT; } private final class ConicalGradientPaintContext implements java.awt.PaintContext { final private java.awt.geom.Point2D CENTER; public ConicalGradientPaintContext(final java.awt.geom.Point2D CENTER) { this.CENTER = new java.awt.geom.Point2D.Double(CENTER.getX(), CENTER.getY()); } @Override public void dispose() { } @Override public java.awt.image.ColorModel getColorModel() { return java.awt.image.ColorModel.getRGBdefault(); } @Override public java.awt.image.Raster getRaster(final int X, final int Y, final int TILE_WIDTH, final int TILE_HEIGHT) { final double ROTATION_CENTER_X = -X + CENTER.getX(); final double ROTATION_CENTER_Y = -Y + CENTER.getY(); final int MAX = FRACTION_ANGLES.length; // Create raster for given colormodel final java.awt.image.WritableRaster RASTER = getColorModel().createCompatibleWritableRaster(TILE_WIDTH, TILE_HEIGHT); // Create data array with place for red, green, blue and alpha values int[] data = new int[(TILE_WIDTH * TILE_HEIGHT * 4)]; double dx; double dy; double distance; double angle; double currentRed = 0; double currentGreen = 0; double currentBlue = 0; double currentAlpha = 0; for (int py = 0; py < TILE_HEIGHT; py++) { for (int px = 0; px < TILE_WIDTH; px++) { // Calculate the distance between the current position and the rotation angle dx = px - ROTATION_CENTER_X; dy = py - ROTATION_CENTER_Y; distance = Math.sqrt(dx * dx + dy * dy); // Avoid division by zero if (distance == 0) { distance = 1; } // 0 degree on top angle = Math.abs(Math.toDegrees(Math.acos(dx / distance))); if (dx >= 0 && dy <= 0) { angle = 90.0 - angle; } else if (dx >= 0 && dy >= 0) { angle += 90.0; } else if (dx <= 0 && dy >= 0) { angle += 90.0; } else if (dx <= 0 && dy <= 0) { angle = 450.0 - angle; } // Check for each angle in fractionAngles array for (int i = 0; i < (MAX - 1); i++) { if ((angle >= FRACTION_ANGLES[i])) { currentRed = COLORS[i].getRed() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * RED_STEP_LOOKUP[i]; currentGreen = COLORS[i].getGreen() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * GREEN_STEP_LOOKUP[i]; currentBlue = COLORS[i].getBlue() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * BLUE_STEP_LOOKUP[i]; currentAlpha = COLORS[i].getAlpha() * INT_TO_FLOAT_CONST + (angle - FRACTION_ANGLES[i]) * ALPHA_STEP_LOOKUP[i]; continue; } } // Fill data array with calculated color values final int BASE = (py * TILE_WIDTH + px) * 4; data[BASE + 0] = (int) (currentRed * 255); data[BASE + 1] = (int) (currentGreen * 255); data[BASE + 2] = (int) (currentBlue * 255); data[BASE + 3] = (int) (currentAlpha * 255); } } // Fill the raster with the data RASTER.setPixels(0, 0, TILE_WIDTH, TILE_HEIGHT, data); return RASTER; } } } } 开始并希望混合到Color.RED,但实际上您需要在它们之间生成每种颜色(基于距离)

例如......

ColorBlend

Color.YELLOW

我知道,它注意到了一个轮子,但是我正在展示混合算法,我会把馅饼切成碎片给你;)

向自己证明它可以起作用......

Color Wheel

import core.ui.ColorUtilities;
import static core.ui.ColorUtilities.blend;
import static core.ui.ColorUtilities.getFractionIndicies;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorWheel {

    public static void main(String[] args) {
        new ColorWheel();
    }

    public ColorWheel() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            float fractions[] = new float[]{0, 0.16f, 0.33f, 0.5f, 0.66f, 0.83f, 1f};
            Color colors[] = new Color[]{Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, Color.RED};
            for (int index = 0; index < getWidth(); index++) {

                float progress = (float) index / getWidth();
                System.out.println(progress);
                Color color = blendColors(fractions, colors, progress);
                g2d.setColor(color);
                g2d.drawLine(index, 0, index, getHeight());
            }

            g2d.dispose();
        }

    }

    /**
     * This will attempt to blend two colors that site between the supplied
     * progress value, based on the distance of the progress value...
     *
     * For example, if you have a series of fractions of {0f, 0.5f, 1f} and a
     * progress of 25%, the resulting color will be a 50% blend of the first and
     * second color (as the progress is half between those two points)
     *
     * @param fractions
     * @param colors
     * @param progress
     * @return
     */
    public static Color blendColors(float[] fractions, Color[] colors, float progress) {

        Color color = null;

        if (fractions != null) {

            if (colors != null) {

                if (fractions.length == colors.length) {

                    int[] indicies = getFractionIndicies(fractions, progress);

                    float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]};
                    Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]};

                    float max = range[1] - range[0];
                    float value = progress - range[0];
                    float weight = value / max;

                    color = blend(colorRange[0], colorRange[1], 1f - weight);

                } else {

                    throw new IllegalArgumentException("Fractions and colours must have equal number of elements");

                }

            } else {

                throw new IllegalArgumentException("Colours can't be null");

            }

        } else {

            throw new IllegalArgumentException("Fractions can't be null");

        }

        return color;

    }
}