java实现渐变效果工具

[html] view plain copy
package gradient;  
  
import java.awt.Color;  
import java.awt.Dimension;  
import java.awt.Graphics;  
import java.awt.Graphics2D;  
import java.awt.Insets;  
import java.awt.LinearGradientPaint;  
import java.awt.MultipleGradientPaint;  
import java.awt.Paint;  
import java.awt.RadialGradientPaint;  
import java.awt.RenderingHints;  
import java.awt.event.KeyAdapter;  
import java.awt.event.KeyEvent;  
import java.awt.event.MouseAdapter;  
import java.awt.event.MouseEvent;  
import java.awt.event.MouseMotionAdapter;  
import java.awt.geom.Ellipse2D;  
import java.awt.geom.GeneralPath;  
import java.awt.geom.Point2D;  
import java.awt.geom.Rectangle2D;  
import java.util.ArrayList;  
import java.util.LinkedList;  
import java.util.List;  
  
import javax.swing.JFrame;  
import javax.swing.JPanel;  
import javax.swing.event.ChangeEvent;  
import javax.swing.event.ChangeListener;  
  
/*  
 使用方法:  
 渐变窗体:  
 a. 左键双击顶点的linear gradient 渐变区,改变渐变超出范围的重复绘制模式.  
 b. 左键双击fractions小按钮区,创建添加一个新的fraction按钮.  
 c. 左键双击fractions小按钮,弹出窗口选择窗口选择颜色.  
 d. 右键双击fractions小按钮,删除此fraction按钮.  
 e. 按住fractions小按钮可以拖动它,修改fractions的位置.  
 f. 左键双击辐射渐变区,改变辐射渐变的焦点(focus)到点击位置.  
 g. 在辐射渐变区按住左键拖动,改变辐射渐变的焦点.  
 h. 按下f,显示辐射渐变的圆周,为了方便看到更清楚的数据,默认这圆周是隐藏的.  
 i. 按下c,恢复辐射渐变的焦点到辐射渐变的圆心,焦点默认是与圆心重合.  
  
 颜色选择窗体:  
 a. 单击某一个颜色,则选中此颜色,并在底部的预览区显示出来.但颜色选择窗口不消失.  
 b. 双击某一个颜色,则选中此颜色,返回给调用者,颜色选择窗口消失.  
 c. 按下回车键,返回选中的颜色,颜色选择窗口消失.  
 d. 按下ESC键,返回传给颜色选择窗体的默认色,颜色选择窗口消失.  
 e. 下部的JSlider依次调节被选中颜色的red, green, blue, alpha,拖动并实时的在预览区显示出调整后颜色.  
  
 第三方程序集成使用方法: 在第三方程序中创建一个GradientGenerator对象,并添加到组件的某一部分,  
 并给此gradientGenerator添加上change listener:  
 gradientGenerator.addChangeListener(new ChangedListener() {   
 public void stateChanged(ChangeEvent e) {   
 float[] fractions = gradientGenerator.getFractons();  
 Color[] colors = gradientGenerator.getColors();  
 Point2D focus = gradientGenerator.calculateFocus(center, radius);  
 repaint(); // 使用这里得到的fractions, colors, focus等去绘制第三方程序中的渐变图形  
 });  
 这样,当gradient generator中的数据发生变化时,第三方程序里也会即时的反映出来.  
  
 1. 提示,现在Swing支持合建不规则窗体。  
 2. 此程序中,除了JSlider,其他的部分都是使用Java2D手动计算绘制出来的。  
 基于上面两点,可以自己创建一个统一的JSlider风格,  
 然后就可以把整个程序的外观风格做得在所有平台下都是一个样。  
 */  
/**  
 * *^o^*,本程序一惯还是一惯的作风,LGPL协议,什么版权的废话就不整了,希望修改得效果好的朋友给大家分享一下心得,在此权当扔出块板砖,  
 * 希望能砸出块暖玉来,嗷呜嗷呜嗷呜.  
 */  
@SuppressWarnings("serial")  
public class GradientGenerator extends JPanel {  
    private int width = 400; // 整个Panel的宽度  
    private int height = 400; // 整个Panel的高度  
    private Insets padding = new Insets(10, 10, 10, 10); // 边距  
  
    private int thumbRectHeight = 20; // Fraction按钮区的高度  
    private int linearRectHeight = 40; // 线性渐变区域的高度  
    private int radialRectHeight = 310; // 辐射渐变区域的高度  
  
    private Ellipse2D radialCircle = new Ellipse2D.Float(); // 辐射渐变的圆周  
    private Point2D focusPoint = new Point2D.Float(); // 辐射渐变的焦点  
    private Point2D pressedPoint = new Point2D.Float(); // 鼠标按下时的点  
    private Rectangle2D linearRect = new Rectangle2D.Float(); // 线性渐变区域  
    private Rectangle2D thumbsRect = new Rectangle2D.Float(); // Fractions按钮区域  
    private Rectangle2D radialRect = new Rectangle2D.Float(); // 辐射渐变区域  
  
    private Thumb selectedThumb = null; // 被选中的Fraction按钮  
    private List<Thumb> thumbs = new ArrayList<Thumb>(); // Fractions按钮  
  
    private boolean showCircle = false; // 显示辐射渐变的圆周  
    private List<ChangeListener> changeListeners = new LinkedList<ChangeListener>();  
    private MultipleGradientPaint.CycleMethod cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;  
  
    /**  
     * 返回渐变的fractions数组  
     *   
     * @return  
     */  
    public float[] getGradientFractions() {  
        float[] fractions = new float[thumbs.size()];  
        int i = 0;  
        for (Thumb t : thumbs) {  
            fractions[i] = (float) ((t.getX() - padding.left) / linearRect.getWidth());  
            ++i;  
        }  
        return fractions;  
    }  
  
    /**  
     * 返回渐变的colors数组  
     *   
     * @return  
     */  
    public Color[] getGradientColors() {  
        Color[] colors = new Color[thumbs.size()];  
        int i = 0;  
        for (Thumb t : thumbs) {  
            colors[i] = t.getColor();  
            ++i;  
        }  
  
        return colors;  
    }  
  
    /**  
     * 利用指定圆的圆心和半径和当前的辐射渐变数据,计算相对于指定圆的焦点  
     *   
     * @param center  
     *        圆心  
     * @param radius  
     *        半径  
     * @return 返回相对于指定圆的焦点  
     */  
    public Point2D calculateFocus(Point2D center, double radius) {  
        Point2D curCenter = new Point2D.Double(radialCircle.getCenterX(), radialCircle.getCenterY());  
        double curRadius = radialCircle.getWidth() / 2;  
        double curFocusLen = GeometryUtil.distanceOfPoints(curCenter, focusPoint);  
  
        double newFocusLen = radius * curFocusLen / curRadius;  
        Point2D newFocusPoint = GeometryUtil.extentPoint(curCenter, focusPoint, newFocusLen);  
        // 先移回原点,再移动到center的位置  
        newFocusPoint.setLocation(center.getX() - curCenter.getX(),  
            center.getY() - curCenter.getY());  
  
        return newFocusPoint;  
    }  
  
    public GradientGenerator() {  
        setFocusable(true); // 为了能接收键盘按键事件  
        afterResized();  
        resetThumbs(new float[] { 0.0f, 0.5f, 1.0f }, new Color[] { Color.BLACK, Color.BLUE,  
                new Color(255, 255, 255, 220) });  
        handleEvents();  
  
        setBackground(Color.DARK_GRAY);  
    }  
  
    // 事件处理  
    private void handleEvents() {  
        this.addMouseListener(new MouseAdapter() {  
            @Override  
            public void mousePressed(MouseEvent e) {  
                int x = e.getX();  
                int y = e.getY();  
                pressedPoint.setLocation(x, y);  
  
                // 得到被选中的Thumb  
                for (Thumb t : thumbs) {  
                    if (t.contains(x, y)) {  
                        t.setSelected(true);  
                        selectedThumb = t;  
                        break;  
                    }  
                }  
                repaint();  
            }  
  
            @Override  
            public void mouseReleased(MouseEvent e) {  
                for (Thumb t : thumbs) {  
                    t.setSelected(false);  
                    selectedThumb = null;  
                }  
                repaint();  
            }  
  
            @Override  
            public void mouseClicked(MouseEvent e) {  
                int x = e.getX();  
                int y = e.getY();  
                // 左键双击  
                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {  
                    // 如果在thumbs里面,则弹出颜色选择器  
                    for (Thumb t : thumbs) {  
                        if (t.contains(x, y)) {  
                            changeThumbColor(t);  
                            repaint();  
                            return;  
                        }  
                    }  
  
                    // 如果不在thumbs里,而在thumbs的区域里,则增加一个thumb  
                    if (thumbsRect.contains(x, y)) {  
                        insertThumbAt(x);  
                        repaint();  
                        return;  
                    }  
  
                    // 修改focus的位置  
                    if (radialRect.contains(x, y)) {  
                        changeFocusPoint(new Point2D.Float(x, y));  
                        repaint();  
                        return;  
                    }  
  
                    // 在Linear rect里面,修改cycle method  
                    if (linearRect.contains(x, y)) {  
                        changeCycleMethod();  
                        repaint();  
                        return;  
                    }  
                } else if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 2) {  
                    // 右键双击  
                    removeThumbAt(x, y);  
                    return;  
                }  
            }  
        });  
  
        this.addMouseMotionListener(new MouseMotionAdapter() {  
            @Override  
            public void mouseDragged(MouseEvent e) {  
                // 拖动滑块  
                if (selectedThumb != null) {  
                    int deltaX = e.getX() - (int) (selectedThumb.getX());  
                    int x = selectedThumb.getX() + deltaX;  
  
                    // 不能超过边界  
                    int maxRight = (int) (padding.left + linearRect.getWidth());  
                    if (x < padding.left || x > maxRight) { return; }  
  
                    int index = thumbs.indexOf(selectedThumb);  
                    int prevX = Integer.MIN_VALUE;  
                    int nextX = Integer.MAX_VALUE;  
                    // 只能在前一个和后一个之间移动  
                    if (index - 1 >= 0) {  
                        prevX = (int) (thumbs.get(index - 1).getX());  
                    }  
  
                    if (index + 1 < thumbs.size()) {  
                        nextX = (int) (thumbs.get(index + 1).getX());  
                    }  
  
                    if (x > prevX && x < nextX) {  
                        selectedThumb.setX(x);  
                        repaint();  
                    }  
                    return;  
                } else if (radialRect.contains(e.getX(), e.getY())) {  
                    int deltaX = (int) (e.getX() - pressedPoint.getX());  
                    int deltaY = (int) (e.getY() - pressedPoint.getY());  
                    focusPoint.setLocation(focusPoint.getX() + deltaX, focusPoint.getY() + deltaY);  
                    pressedPoint.setLocation(e.getX(), e.getY());  
                    repaint();  
                }  
  
            }  
        });  
  
        this.addKeyListener(new KeyAdapter() {  
            @Override  
            public void keyReleased(KeyEvent e) {  
                switch (e.getKeyCode()) {  
                case KeyEvent.VK_F:  
                    showCircle = !showCircle;  
                    break;  
                case KeyEvent.VK_C:  
                    changeFocusPoint(radialCircle.getCenterX(), radialCircle.getCenterY());  
                    break;  
                }  
                repaint();  
            }  
        });  
    }  
  
    // 执行监听器的事件  
    public void fireChangeEvent() {  
        for (ChangeListener l : changeListeners) {  
            l.stateChanged(new ChangeEvent(this));  
        }  
    }  
  
    // 改变超出渐变区的颜色渐变方式  
    public void changeCycleMethod() {  
        changeCycleMethod(cycleMethod);  
    }  
  
    public void changeCycleMethod(MultipleGradientPaint.CycleMethod cycleMethod) {  
        switch (cycleMethod) {  
        case NO_CYCLE:  
            this.cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;  
            break;  
        case REFLECT:  
            this.cycleMethod = MultipleGradientPaint.CycleMethod.REPEAT;  
            break;  
        case REPEAT:  
            this.cycleMethod = MultipleGradientPaint.CycleMethod.NO_CYCLE;  
            break;  
        }  
    }  
  
    @Override  
    protected void paintComponent(Graphics g) {  
        super.paintComponent(g);  
        Graphics2D g2d = (Graphics2D) g;  
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
  
        drawLinearRect(g2d);  
        drawThumbsRect(g2d);  
        drawRadialRect(g2d);  
    }  
  
    // 绘制fraction按钮所在区域  
    private void drawThumbsRect(Graphics2D g2d) {  
        g2d.setColor(new Color(255, 255, 255, 40));  
        g2d.fill(thumbsRect);  
  
        // 绘制fraction按钮  
        for (Thumb t : thumbs) {  
            t.paint(g2d);  
        }  
    }  
  
    private void drawLinearRect(Graphics2D g2d) {  
        // 绘制线性渐变区域  
        float sx = (float) linearRect.getX();  
        float sy = (float) linearRect.getY();  
        float ex = (int) (sx + linearRect.getWidth());  
        float ey = sy;  
        float[] fractions = getGradientFractions();  
        Color[] colors = getGradientColors();  
        Paint p = new LinearGradientPaint(sx, sy, ex, ey, fractions, colors, cycleMethod);  
  
        TransparentPainter.paint(g2d, linearRect);  
        g2d.setPaint(p);  
        g2d.fill(linearRect);  
    }  
  
    // 绘制辐射渐变区  
    private void drawRadialRect(Graphics2D g2d) {  
        float cx = (float) radialCircle.getCenterX();  
        float cy = (float) radialCircle.getCenterY();  
        float fx = (float) focusPoint.getX();  
        float fy = (float) focusPoint.getY();  
        float radius = (float) radialCircle.getWidth() / 2;  
        float[] fractions = getGradientFractions();  
        Color[] colors = getGradientColors();  
  
        TransparentPainter.paint(g2d, radialRect);  
  
        Paint p = new RadialGradientPaint(cx, cy, radius, fx, fy, fractions, colors, cycleMethod);  
        g2d.setPaint(p);  
        g2d.fill(radialRect);  
  
        if (showCircle) {  
            // 绘制辐射渐变的圆  
            g2d.setPaint(Color.BLACK);  
            g2d.draw(radialCircle);  
        }  
    }  
  
    // 最少需要两个渐变值,所以开始就创建两个fraction  
    public void resetThumbs(float[] fractions, Color[] colors) {  
        if (fractions == null || colors == null) { throw new NullPointerException(); }  
        if (fractions.length != colors.length) { throw new IllegalArgumentException(  
            "Fractions 和 Colors 参数个数不等"); }  
  
        int x = (int) thumbsRect.getX();  
        int w = (int) thumbsRect.getWidth();  
        for (int i = 0; i < fractions.length; ++i) {  
            insertThumbAt(x + (int) (w * fractions[i]), colors[i]);  
        }  
    }  
  
    // 在指定的水平位置插入Fraction按钮  
    private void insertThumbAt(int x) {  
        insertThumbAt(x, Color.BLUE);  
    }  
  
    private void insertThumbAt(int x, Color color) {  
        int index = 0;  
        for (Thumb t : thumbs) {  
            if (x > t.getX()) {  
                index++;  
            }  
        }  
  
        int y = (int) (padding.top + linearRect.getHeight());  
        thumbs.add(index, new Thumb(x, y, color));  
  
        fireChangeEvent();  
    }  
  
    public void removeThumbAt(int x, int y) {  
        for (Thumb t : thumbs) {  
            if (t.contains(x, y)) {  
                if (thumbs.size() > 2) {  
                    thumbs.remove(t);  
                    fireChangeEvent();  
                    break;  
                }  
            }  
        }  
    }  
  
    private void changeThumbColor(Thumb thumb) {  
        // 弹出颜色选择器  
        Color newColor = ColorChooser.chooseColor(this, thumb.getColor());  
        if (newColor != null) {  
            thumb.setColor(newColor);  
            fireChangeEvent();  
        }  
    }  
  
    // 改变焦点的位置  
    public void changeFocusPoint(double x, double y) {  
        focusPoint.setLocation(x, y);  
        fireChangeEvent();  
    }  
  
    private void changeFocusPoint(Point2D focusPoint) {  
        changeFocusPoint(focusPoint.getX(), focusPoint.getY());  
    }  
  
    // 当panel的大小改变时,再次调用此函数更新显示区域  
    private void afterResized() {  
        // ////////////////////////////////////////  
        // padding-top  
        // linear gradient area  
        // thumbs area  
        // padding = padding top  
        // radial gradient area  
        // padding-bottom  
        // ///////////////////////////////////////  
  
        // 线性渐变显示区域  
        int x = padding.left;  
        int y = padding.top;  
        int w = width - padding.left - padding.right;  
        int h = linearRectHeight;  
        linearRect.setRect(x, y, w, h);  
  
        // Fraction按钮所在区域  
        y += linearRectHeight;  
        h = thumbRectHeight;  
        thumbsRect.setRect(x, y, w, h);  
  
        // 辐射渐变显示区域  
        y = padding.top + linearRectHeight + thumbRectHeight + padding.top;  
        h = radialRectHeight;  
        h = Math.min(w, h);  
        x = (width - w) / 2;  
        radialRect.setRect(x, y, w, h);  
  
        // 中心点和焦点  
        int cx = x + w / 2;  
        int cy = y + h / 2;  
        int radius = 100;  
        focusPoint.setLocation(cx, cy);  
        radialCircle.setFrame(cx - radius, cy - radius, radius + radius, radius + radius);  
  
        repaint();  
    }  
  
    @Override  
    public Dimension getMinimumSize() {  
        return new Dimension(width, height);  
    }  
  
    @Override  
    public Dimension getMaximumSize() {  
        return new Dimension(width, height);  
    }  
  
    @Override  
    public Dimension getPreferredSize() {  
        return new Dimension(width, height);  
    }  
  
    private static void createGuiAndShow() {  
        JFrame frame = new JFrame("Gradient Generator");  
        JPanel panel = new JPanel();  
        panel.add(new GradientGenerator());  
        frame.setContentPane(new GradientGenerator());  
  
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        frame.pack(); // 使用此函数后always on top就不起作用了  
        frame.setResizable(false);  
        frame.setLocationRelativeTo(null);  
        frame.setAlwaysOnTop(true);  
        frame.setVisible(true);  
    }  
  
    public static void main(String[] args) {  
        createGuiAndShow();  
    }  
}  
  
class Thumb {  
    private int x;  
    private int y;  
    private int width = 16;  
    private int height = 20;  
    private Color color;  
    private boolean selected;  
  
    private GeneralPath outerPath;  
    private GeneralPath innerPath;  
  
    public Thumb(int x, int y, Color color) {  
        setXY(x, y);  
        this.color = color;  
    }  
  
    public int getX() {  
        return x;  
    }  
  
    public void setX(int x) {  
        setXY(x, y);  
    }  
  
    public int getY() {  
        return y;  
    }  
  
    public void setY(int y) {  
        setXY(x, y);  
    }  
  
    public int getWidth() {  
        return width;  
    }  
  
    public void setWidth(int width) {  
        setWidthHeight(width, height);  
    }  
  
    public int getHeight() {  
        return height;  
    }  
  
    public void setHeight(int height) {  
        setWidthHeight(width, height);  
    }  
  
    public Color getColor() {  
        return color;  
    }  
  
    public void setColor(Color color) {  
        this.color = color;  
    }  
  
    public boolean isSelected() {  
        return selected;  
    }  
  
    public void setSelected(boolean selected) {  
        this.selected = selected;  
    }  
  
    public boolean contains(int x, int y) {  
        return outerPath.contains(x, y);  
    }  
  
    public void setXY(int x, int y) {  
        this.x = x;  
        this.y = y;  
        createPaths();  
    }  
  
    public void setWidthHeight(int width, int height) {  
        this.width = width;  
        this.height = height;  
        createPaths();  
    }  
  
    private float[] fractions = new float[] { 0.0f, 0.5f, 1.0f };  
    private Color[] colors = new Color[] { Color.ORANGE, Color.BLACK, Color.ORANGE.brighter() };  
  
    public void paint(Graphics2D g2d) {  
        // 绘制大三角形按钮  
        // Paint p = new GradientPaint(x, y, selected ? color.darker() : color,  
        // x, y + height, Color.ORANGE);  
        Paint p = new LinearGradientPaint(x - width, y, x + width / 4, y, fractions, colors);  
        g2d.setPaint(p);  
        g2d.fill(outerPath);  
  
        // 绘制小三角形按钮  
        g2d.setColor(color);  
        g2d.fill(innerPath);  
    }  
  
    // 创建按钮的形状  
    private void createPaths() {  
        outerPath = new GeneralPath();  
        outerPath.moveTo(x, y);  
        outerPath.lineTo(x + width / 2, y + height);  
        outerPath.lineTo(x - width / 2, y + height);  
        outerPath.closePath();  
  
        innerPath = new GeneralPath();  
        innerPath.moveTo(x, y + height / 2);  
        innerPath.lineTo(x + width / 4, y + height);  
        innerPath.lineTo(x - width / 4, y + height);  
        innerPath.closePath();  
    }  
}  

 
[html] view plain copy
package gradient;  
  
import java.awt.AWTEvent;  
import java.awt.BorderLayout;  
import java.awt.Color;  
import java.awt.Component;  
import java.awt.Dimension;  
import java.awt.Graphics;  
import java.awt.Graphics2D;  
import java.awt.Insets;  
import java.awt.RenderingHints;  
import java.awt.Toolkit;  
import java.awt.event.AWTEventListener;  
import java.awt.event.KeyEvent;  
import java.awt.event.MouseAdapter;  
import java.awt.event.MouseEvent;  
import java.awt.event.WindowAdapter;  
import java.awt.event.WindowEvent;  
import java.awt.geom.Rectangle2D;  
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.FileNotFoundException;  
import java.util.ArrayList;  
import java.util.List;  
import java.util.Scanner;  
  
import javax.swing.JComponent;  
import javax.swing.JDialog;  
import javax.swing.JPanel;  
import javax.swing.JSlider;  
import javax.swing.event.ChangeEvent;  
import javax.swing.event.ChangeListener;  
  
/**  
 * 创建一个模态的颜色选择对话框,可以加载用户预先定义存储好的颜色.  
 *   
 * @author Biao  
 *   
 */  
@SuppressWarnings("serial")  
public class ColorChooser extends JDialog {  
    private static ColorChooser instance = new ColorChooser();  
    private ColorPanel colorPanel = new ColorPanel();  
    private Color color;  
  
    public static Color chooseColor(JComponent ower, Color defaultColor) {  
        instance.color = defaultColor;  
        instance.colorPanel.startSelect(defaultColor);  
  
        instance.pack();  
        instance.setLocationRelativeTo(ower);  
        instance.setVisible(true);  
  
        return instance.color;  
    }  
  
    private ColorChooser() {  
        setTitle("Choose a color");  
        setModal(true);  
        setResizable(false);  
        setBackground(Color.DARK_GRAY);  
        getContentPane().add(colorPanel, BorderLayout.CENTER);  
  
        this.addWindowListener(new WindowAdapter() {  
            @Override  
            public void windowClosing(WindowEvent e) {  
                gotoHell(color);  
            }  
        });  
  
        colorPanel.addChangeListener(new ChangeListener() {  
            @Override  
            public void stateChanged(ChangeEvent e) {  
                Color c = colorPanel.getColor();  
                if (colorPanel.isDoubleClickSelection()) {  
                    gotoHell(c);  
                }  
  
                int r = c.getRed();  
                int g = c.getGreen();  
                int b = c.getBlue();  
                int a = c.getAlpha();  
  
                String hex = ColorPanel.colorToHexString(new Color(r, g, b, a));  
                String title = String.format("RGBA(%d,%d,%d,%d) Hex(%s)", r, g, b, a, hex);  
                setTitle(title);  
            }  
        });  
  
        // 处理JDialog所有子组件的按键事件  
        // 按下回车使用选择的颜色,按下Esc返回默认传进来的颜色  
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {  
            @Override  
            public void eventDispatched(AWTEvent event) {  
                KeyEvent ke = (KeyEvent) event;  
  
                if (ke.getID() == KeyEvent.KEY_PRESSED) {  
                    if (event.getSource() instanceof Component) {  
                        Component com = (Component) event.getSource();  
                        if (ke.getKeyCode() == KeyEvent.VK_ESCAPE && hasChild(com)) {  
                            gotoHell(color); // 取消时返回默认的颜色  
                        } else if (ke.getKeyCode() == KeyEvent.VK_ENTER && hasChild(com)) {  
                            gotoHell(colorPanel.getColor());  
                        }  
                    }  
                }  
            }  
        }, AWTEvent.KEY_EVENT_MASK);  
    }  
  
    // 是否包含了组件  
    public boolean hasChild(Component c) {  
        for (Component parent = c; parent != null; parent = parent.getParent()) {  
            if (parent == this) { return true; }  
        }  
        return false;  
    }  
  
    // 隐藏颜色选择对话框  
    public void gotoHell(Color c) {  
        color = (c == null) ? color : c;  
        setVisible(false);  
    }  
}  
  
@SuppressWarnings("serial")  
class ColorPanel extends JPanel {  
    final static private int columnSize = 21; // 每行最多显示21个颜色  
    final static private int sliderHeight = 20; // Slider的高度  
    final static private int previewHeight = 20; // 预览区的高度  
    final static private int colorRectWidth = 20; // 颜色小方块的宽度  
    final static private int colorRectHeight = 20;// 颜色小方块的高度  
  
    private int width = 520; // Color panel的尺寸  
    private int height = 340;  
    private Insets padding = new Insets(10, 10, 0, 10); // 边距  
  
    private int margin = padding.top;  
    private Color color = Color.WHITE;  
    private List<Color> storedColors = new ArrayList<Color>(); // 用户存储的颜色  
    private List<Color> defaultColors = new ArrayList<Color>(); // 使用算法生成的默认颜色  
    private Rectangle2D previewRect = new Rectangle2D.Float(); // 预览区域  
    private Rectangle2D colorsImageRect = new Rectangle2D.Double(); // 显示颜色的区域  
    private BufferedImage colorsImage; // 需要使用颜色信息来创建确定大小  
  
    // 调节rgba的slider  
    private JSlider redSlider = new JSlider(0, 255, 255);  
    private JSlider greenSlider = new JSlider(0, 255, 255);  
    private JSlider blueSlider = new JSlider(0, 255, 255);  
    private JSlider alphaSlider = new JSlider(0, 255, 255);  
  
    // 双击时如果选中颜色,则选择完成  
    private boolean doubleClickSelection = false;  
    private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>();  
  
    public ColorPanel() {  
        // 创建颜色和显示颜色的小方块缓冲图像  
        prepareColors();  
        prepareColorsImage();  
        // 窗口的大小需要用color buffer image的大小来确定,所以必须在这里调用  
        prepareSize();  
  
        preparePreview();  
        prepareSliders();  
  
        this.addMouseListener(new MouseAdapter() {  
            @Override  
            public void mouseClicked(MouseEvent e) {  
                int x = e.getX();  
                int y = e.getY();  
                Color c = getColorAt(x, y);  
  
                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 1) {  
                    // 单击时设置选中的颜色  
                    if (c != null) {  
                        setColor(c);  
                        fireStateChanged();  
                    }  
                } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {  
                    // 双击时返回选中的颜色,隐藏颜色选取窗口  
                    if (c != null || previewRect.contains(x, y)) {  
                        setDoubleClickSelection(true);  
                        fireStateChanged();  
                    }  
                }  
            }  
        });  
  
        redSlider.addChangeListener(new ChangeListener() {  
            @Override  
            public void stateChanged(ChangeEvent e) {  
                setR(redSlider.getValue());  
                fireStateChanged();  
            }  
        });  
  
        greenSlider.addChangeListener(new ChangeListener() {  
            @Override  
            public void stateChanged(ChangeEvent e) {  
                setG(greenSlider.getValue());  
                fireStateChanged();  
            }  
        });  
  
        blueSlider.addChangeListener(new ChangeListener() {  
            @Override  
            public void stateChanged(ChangeEvent e) {  
                setB(blueSlider.getValue());  
                fireStateChanged();  
            }  
        });  
  
        alphaSlider.addChangeListener(new ChangeListener() {  
            @Override  
            public void stateChanged(ChangeEvent e) {  
                setA(alphaSlider.getValue());  
                fireStateChanged();  
            }  
        });  
    }  
  
    @Override  
    protected void paintComponent(Graphics g) {  
        super.paintComponent(g);  
        setBackground(Color.DARK_GRAY);  
        Graphics2D g2d = (Graphics2D) g;  
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
  
        // 绘制颜色方块的缓冲图片  
        int x = (int) colorsImageRect.getX();  
        int y = (int) colorsImageRect.getY();  
        int w = (int) colorsImageRect.getWidth();  
        int h = (int) colorsImageRect.getHeight();  
        g2d.drawImage(colorsImage, x, y, w, h, null);  
  
        // 绘制颜色预览  
        TransparentPainter.paint(g2d, previewRect);  
        g2d.setPaint(color);  
        g2d.fill(previewRect);  
    }  
  
    public void startSelect(Color color) {  
        setColor(color);  
        setDoubleClickSelection(false);  
    }  
  
    public boolean isDoubleClickSelection() {  
        return doubleClickSelection;  
    }  
  
    protected void setDoubleClickSelection(boolean doubleClickSelection) {  
        this.doubleClickSelection = doubleClickSelection;  
    }  
  
    // 当属性改变事件发生时,调用监听器并且重绘  
    public void fireStateChanged() {  
        for (ChangeListener l : changeListeners) {  
            l.stateChanged(new ChangeEvent(this));  
        }  
        repaint();  
    }  
  
    public void addChangeListener(ChangeListener l) {  
        changeListeners.add(l);  
    }  
  
    public void removeChangeListener(ChangeListener l) {  
        changeListeners.remove(l);  
    }  
  
    // 选得鼠标选中的颜色  
    public Color getColorAt(int x, int y) {  
        // 如果不在显示颜色的图片中,则返回null  
        if (!colorsImageRect.contains(x, y)) { return null; }  
  
        // 以图片的左上角为原点  
        x -= colorsImageRect.getX();  
        y -= colorsImageRect.getY();  
  
        if (y <= getHeightOfColorsRect(storedColors)) {  
            int i = y / colorRectHeight * columnSize + x / colorRectWidth;  
            return i >= storedColors.size() ? null : storedColors.get(i);  
        } else {  
            y -= getHeightOfColorsRect(storedColors) + margin;  
            int i = y / colorRectHeight * columnSize + x / colorRectWidth;  
            return i >= defaultColors.size() ? null : defaultColors.get(i);  
        }  
    }  
  
    // 返回当前选中的颜色  
    public Color getColor() {  
        return color;  
    }  
  
    // 设置当前颜色  
    public void setColor(Color color) {  
        this.color = (color == null) ? Color.WHITE : color;  
        setSliderValues(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());  
    }  
  
    public void setColor(int r, int g, int b) {  
        this.color = new Color(r, g, b, 255);  
        setSliderValues(r, g, b, 255);  
    }  
  
    public void setColor(int r, int g, int b, int a) {  
        r = clamp(r);  
        g = clamp(g);  
        b = clamp(b);  
        a = clamp(a);  
        this.color = new Color(r, g, b, a);  
        setSliderValues(r, g, b, a);  
    }  
  
    public void setR(int r) {  
        setColor(r, color.getGreen(), color.getBlue(), color.getAlpha());  
    }  
  
    public void setG(int g) {  
        setColor(color.getRed(), g, color.getBlue(), color.getAlpha());  
    }  
  
    public void setB(int b) {  
        setColor(color.getRed(), color.getGreen(), b, color.getAlpha());  
    }  
  
    public void setA(int a) {  
        setColor(color.getRed(), color.getGreen(), color.getBlue(), a);  
    }  
  
    public int clamp(int val) {  
        val = val < 0 ? 0 : val;  
        val = val > 255 ? 255 : val;  
        return val;  
    }  
  
    // 设置slier的值  
    private void setSliderValues(int r, int g, int b, int a) {  
        redSlider.setValue(r);  
        greenSlider.setValue(g);  
        blueSlider.setValue(b);  
        alphaSlider.setValue(a);  
  
        fireStateChanged();  
    }  
  
    /**  
     * 把16进制模式的字符串转化成颜色.  
     *   
     * @param hex  
     *        表示颜色的16进制字符串,格式为#rgb, #rrggbb, #aarrggbb  
     * @return 返回字符串的颜色,如果字符串格式不对,返回null  
     */  
    public static Color parseColorHex(String hex) {  
        // #rgb, #rrggbb, #aarrggbb  
        // 检查长度  
        if (hex == null || hex.length() != 4 && hex.length() != 7 && hex.length() != 9  
                && hex.charAt(0) != '#') { return null; }  
  
        // 检查字符是否有效  
        for (int i = 1; i < hex.length(); ++i) {  
            char aChar = hex.charAt(i);  
            if (!('0' <= aChar && aChar <= '9') && !('a' <= aChar && aChar <= 'f')  
                    && !('A' <= aChar && aChar <= 'F')) { return null; }  
        }  
  
        if (hex.length() == 4) {  
            // #rgb  
            int r = Integer.valueOf(hex.charAt(1) + "" + hex.charAt(1), 16);  
            int g = Integer.valueOf(hex.charAt(2) + "" + hex.charAt(2), 16);  
            int b = Integer.valueOf(hex.charAt(3) + "" + hex.charAt(3), 16);  
            return new Color(r, g, b);  
        } else if (hex.length() == 7) {  
            // #rrggbb  
            int r = Integer.valueOf(hex.substring(1, 3), 16);  
            int g = Integer.valueOf(hex.substring(3, 5), 16);  
            int b = Integer.valueOf(hex.substring(5, 7), 16);  
            return new Color(r, g, b);  
        } else if (hex.length() == 9) {  
            // #aarrggbb  
            int a = Integer.valueOf(hex.substring(1, 3), 16);  
            int r = Integer.valueOf(hex.substring(3, 5), 16);  
            int g = Integer.valueOf(hex.substring(5, 7), 16);  
            int b = Integer.valueOf(hex.substring(7, 9), 16);  
            return new Color(r, g, b, a);  
        }  
  
        return null;  
    }  
  
    public static char[] hexDight = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',  
            'C', 'D', 'E', 'F' };  
  
    /**  
     * 把颜色的表示转换为16进制表示#rrggbbaa  
     *   
     * @param color  
     * @return 返回颜色的16进制字符串  
     */  
    public static String colorToHexString(Color color) {  
        if (color == null) { return "null"; }  
        int r = color.getRed();  
        int g = color.getGreen();  
        int b = color.getBlue();  
        int a = color.getAlpha();  
  
        StringBuilder sb = new StringBuilder("#");  
        sb.append(hexDight[a >> 4 & 0xF]);  
        sb.append(hexDight[a & 0xF]);  
        sb.append(hexDight[r >> 4 & 0xF]);  
        sb.append(hexDight[r & 0xF]);  
        sb.append(hexDight[g >> 4 & 0xF]);  
        sb.append(hexDight[g & 0xF]);  
        sb.append(hexDight[b >> 4 & 0xF]);  
        sb.append(hexDight[b & 0xF]);  
  
        return sb.toString();  
    }  
  
    private void prepareColors() {  
        // 从文件中读取颜色  
        try {  
            Scanner scanner = new Scanner(new File("resources/colors.txt"));  
            while (scanner.hasNextLine()) {  
                try {  
                    Color c = parseColorHex(scanner.nextLine().trim());  
                    if (c != null) {  
                        storedColors.add(c);  
                    }  
                } catch (Exception e) {  
                }  
            }  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        }  
  
        // 创建一些默认的颜色  
        final float delta = 0.2f;  
        for (float r = 0; r <= 1.0; r += delta) {  
            for (float g = 0; g <= 1.0; g += delta) {  
                for (float b = 0; b <= 1.0; b += delta) {  
                    defaultColors.add(new Color(r, g, b));  
                }  
            }  
        }  
    }  
  
    private int getHeightOfColorsRect(List<Color> li) {  
        int row = (int) Math.ceil(li.size() / (float) columnSize);  
  
        return row * colorRectWidth;  
    }  
  
    private void prepareColorsImage() {  
        margin = padding.top;  
        int w = columnSize * colorRectWidth;  
        int h = getHeightOfColorsRect(storedColors) + getHeightOfColorsRect(defaultColors) + margin;  
        int x = 0;  
        int y = 0;  
  
        colorsImageRect.setRect(padding.top, padding.top, w, h);  
        colorsImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);  
        Graphics2D g2d = colorsImage.createGraphics();  
  
        // 绘制用户存储的颜色  
        for (int i = 0; i < storedColors.size(); ++i) {  
            g2d.setPaint(storedColors.get(i));  
            g2d.fillRect(x, y, colorRectWidth, colorRectHeight);  
  
            x += colorRectWidth;  
  
            if ((i + 1) % columnSize == 0) {  
                x = 0;  
                y += colorRectHeight;  
            }  
        }  
  
        x = 0;  
        y = getHeightOfColorsRect(storedColors) + margin;  
  
        // 绘制默认的颜色  
        for (int i = 0; i < defaultColors.size(); ++i) {  
            g2d.setPaint(defaultColors.get(i));  
            g2d.fillRect(x, y, colorRectWidth, colorRectHeight);  
  
            x += colorRectWidth;  
  
            if ((i + 1) % columnSize == 0) {  
                x = 0;  
                y += colorRectHeight;  
            }  
        }  
    }  
  
    private void prepareSize() {  
        width = padding.left + colorsImage.getWidth() + padding.right;  
        height = padding.top + colorsImage.getHeight() + padding.top + previewHeight + sliderHeight;  
    }  
  
    private void preparePreview() {  
        int x = padding.left;  
        int y = height - sliderHeight - previewHeight;  
        int w = width - padding.left - padding.right;  
        previewRect.setRect(x, y, w, previewHeight);  
    }  
  
    private void prepareSliders() {  
        setLayout(null);  
        int margin = 0; // slider之间的间隔,实际没必须  
        int h = sliderHeight;  
        int w = (width - padding.left - padding.right) / 4;  
        int x = padding.left;  
        int y = height - h + 2;  
  
        redSlider.setBounds(x, y, w, h);  
        x += w + margin;  
        greenSlider.setBounds(x, y, w, h);  
        x += w + margin;  
        blueSlider.setBounds(x, y, w, h);  
        x += w + margin;  
        alphaSlider.setBounds(x, y, w, h);  
  
        add(redSlider);  
        add(greenSlider);  
        add(blueSlider);  
        add(alphaSlider);  
    }  
  
    @Override  
    public Dimension getMinimumSize() {  
        return new Dimension(width, height);  
    }  
  
    @Override  
    public Dimension getMaximumSize() {  
        return new Dimension(width, height);  
    }  
  
    @Override  
    public Dimension getPreferredSize() {  
        return new Dimension(width, height);  
    }  
}  

 
[html] view plain copy
package gradient;  
  
import java.awt.Color;  
import java.awt.Graphics2D;  
import java.awt.geom.Rectangle2D;  
  
/**  
 * 绘制Photoshop中透明色的效果.  
 *   
 * @author Biao  
 *   
 */  
public class TransparentPainter {  
    public static void paint(Graphics2D g2d, Rectangle2D rect) {  
        g2d.setClip(rect);  
        int sx = (int) rect.getX();  
        int sy = (int) rect.getY();  
        int w = (int) rect.getWidth();  
        int h = (int) rect.getHeight();  
  
        Color color = Color.WHITE;  
        Color color1 = Color.WHITE;  
        Color color2 = Color.LIGHT_GRAY;  
        int delta = 10;  
        boolean odd = false;  
        for (int y = sy; y <= h + sy; y += delta) {  
            color = (odd) ? color1 : color2;  
            for (int x = sx; x <= w + sx; x += delta) {  
                g2d.setPaint(color);  
                g2d.fillRect(x, y, w, h);  
  
                color = (color == color1) ? color2 : color1;  
            }  
  
            odd = !odd;  
        }  
        g2d.setClip(null);  
    }  
}  

 
[html] view plain copy
package gradient;  
import java.awt.geom.Point2D;  
  
public class GeometryUtil {  
    // 两点之间的距离  
    public static double distanceOfPoints(Point2D p1, Point2D p2) {  
        double disX = p2.getX() - p1.getX();  
        double disY = p2.getY() - p1.getY();  
        double dis = Math.sqrt(disX * disX + disY * disY);  
  
        return dis;  
    }  
  
    // 两点的中点  
    public static Point2D middlePoint(Point2D p1, Point2D p2) {  
        double x = (p1.getX() + p2.getX()) / 2;  
        double y = (p1.getY() + p2.getY()) / 2;  
  
        return new Point2D.Double(x, y);  
    }  
  
    // 在两点所在直线上,以从startPoint到endPoint为方向,离startPoint的距离disToStartPoint的点  
    public static Point2D extentPoint(Point2D startPoint, Point2D endPoint, double disToStartPoint) {  
        double disX = endPoint.getX() - startPoint.getX();  
        double disY = endPoint.getY() - startPoint.getY();  
        double dis = Math.sqrt(disX * disX + disY * disY);  
        double sin = (endPoint.getY() - startPoint.getY()) / dis;  
        double cos = (endPoint.getX() - startPoint.getX()) / dis;  
        double deltaX = disToStartPoint * cos;  
        double deltaY = disToStartPoint * sin;  
  
        return new Point2D.Double(startPoint.getX() + deltaX, startPoint.getY() + deltaY);  
    }  
}  

 

  1. package gradient;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Dimension;  
  5. import java.awt.Graphics;  
  6. import java.awt.Graphics2D;  
  7. import java.awt.Insets;  
  8. import java.awt.LinearGradientPaint;  
  9. import java.awt.MultipleGradientPaint;  
  10. import java.awt.Paint;  
  11. import java.awt.RadialGradientPaint;  
  12. import java.awt.RenderingHints;  
  13. import java.awt.event.KeyAdapter;  
  14. import java.awt.event.KeyEvent;  
  15. import java.awt.event.MouseAdapter;  
  16. import java.awt.event.MouseEvent;  
  17. import java.awt.event.MouseMotionAdapter;  
  18. import java.awt.geom.Ellipse2D;  
  19. import java.awt.geom.GeneralPath;  
  20. import java.awt.geom.Point2D;  
  21. import java.awt.geom.Rectangle2D;  
  22. import java.util.ArrayList;  
  23. import java.util.LinkedList;  
  24. import java.util.List;  
  25.   
  26. import javax.swing.JFrame;  
  27. import javax.swing.JPanel;  
  28. import javax.swing.event.ChangeEvent;  
  29. import javax.swing.event.ChangeListener;  
  30.   
  31. /*  
  32.  使用方法:  
  33.  渐变窗体:  
  34.  a. 左键双击顶点的linear gradient 渐变区,改变渐变超出范围的重复绘制模式.  
  35.  b. 左键双击fractions小按钮区,创建添加一个新的fraction按钮.  
  36.  c. 左键双击fractions小按钮,弹出窗口选择窗口选择颜色.  
  37.  d. 右键双击fractions小按钮,删除此fraction按钮.  
  38.  e. 按住fractions小按钮可以拖动它,修改fractions的位置.  
  39.  f. 左键双击辐射渐变区,改变辐射渐变的焦点(focus)到点击位置.  
  40.  g. 在辐射渐变区按住左键拖动,改变辐射渐变的焦点.  
  41.  h. 按下f,显示辐射渐变的圆周,为了方便看到更清楚的数据,默认这圆周是隐藏的.  
  42.  i. 按下c,恢复辐射渐变的焦点到辐射渐变的圆心,焦点默认是与圆心重合.  
  43.   
  44.  颜色选择窗体:  
  45.  a. 单击某一个颜色,则选中此颜色,并在底部的预览区显示出来.但颜色选择窗口不消失.  
  46.  b. 双击某一个颜色,则选中此颜色,返回给调用者,颜色选择窗口消失.  
  47.  c. 按下回车键,返回选中的颜色,颜色选择窗口消失.  
  48.  d. 按下ESC键,返回传给颜色选择窗体的默认色,颜色选择窗口消失.  
  49.  e. 下部的JSlider依次调节被选中颜色的red, green, blue, alpha,拖动并实时的在预览区显示出调整后颜色.  
  50.   
  51.  第三方程序集成使用方法: 在第三方程序中创建一个GradientGenerator对象,并添加到组件的某一部分,  
  52.  并给此gradientGenerator添加上change listener:  
  53.  gradientGenerator.addChangeListener(new ChangedListener() {   
  54.  public void stateChanged(ChangeEvent e) {   
  55.  float[] fractions = gradientGenerator.getFractons();  
  56.  Color[] colors = gradientGenerator.getColors();  
  57.  Point2D focus = gradientGenerator.calculateFocus(center, radius);  
  58.  repaint(); // 使用这里得到的fractions, colors, focus等去绘制第三方程序中的渐变图形  
  59.  });  
  60.  这样,当gradient generator中的数据发生变化时,第三方程序里也会即时的反映出来.  
  61.   
  62.  1. 提示,现在Swing支持合建不规则窗体。  
  63.  2. 此程序中,除了JSlider,其他的部分都是使用Java2D手动计算绘制出来的。  
  64.  基于上面两点,可以自己创建一个统一的JSlider风格,  
  65.  然后就可以把整个程序的外观风格做得在所有平台下都是一个样。  
  66.  */  
  67. /**  
  68.  * *^o^*,本程序一惯还是一惯的作风,LGPL协议,什么版权的废话就不整了,希望修改得效果好的朋友给大家分享一下心得,在此权当扔出块板砖,  
  69.  * 希望能砸出块暖玉来,嗷呜嗷呜嗷呜.  
  70.  */  
  71. @SuppressWarnings("serial")  
  72. public class GradientGenerator extends JPanel {  
  73.     private int width = 400; // 整个Panel的宽度  
  74.     private int height = 400; // 整个Panel的高度  
  75.     private Insets padding = new Insets(10, 10, 10, 10); // 边距  
  76.   
  77.     private int thumbRectHeight = 20; // Fraction按钮区的高度  
  78.     private int linearRectHeight = 40; // 线性渐变区域的高度  
  79.     private int radialRectHeight = 310; // 辐射渐变区域的高度  
  80.   
  81.     private Ellipse2D radialCircle = new Ellipse2D.Float(); // 辐射渐变的圆周  
  82.     private Point2D focusPoint = new Point2D.Float(); // 辐射渐变的焦点  
  83.     private Point2D pressedPoint = new Point2D.Float(); // 鼠标按下时的点  
  84.     private Rectangle2D linearRect = new Rectangle2D.Float(); // 线性渐变区域  
  85.     private Rectangle2D thumbsRect = new Rectangle2D.Float(); // Fractions按钮区域  
  86.     private Rectangle2D radialRect = new Rectangle2D.Float(); // 辐射渐变区域  
  87.   
  88.     private Thumb selectedThumb = null; // 被选中的Fraction按钮  
  89.     private List<Thumb> thumbs = new ArrayList<Thumb>(); // Fractions按钮  
  90.   
  91.     private boolean showCircle = false; // 显示辐射渐变的圆周  
  92.     private List<ChangeListener> changeListeners = new LinkedList<ChangeListener>();  
  93.     private MultipleGradientPaint.CycleMethod cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;  
  94.   
  95.     /**  
  96.      * 返回渐变的fractions数组  
  97.      *   
  98.      * @return  
  99.      */  
  100.     public float[] getGradientFractions() {  
  101.         float[] fractions = new float[thumbs.size()];  
  102.         int i = 0;  
  103.         for (Thumb t : thumbs) {  
  104.             fractions[i] = (float) ((t.getX() - padding.left) / linearRect.getWidth());  
  105.             ++i;  
  106.         }  
  107.         return fractions;  
  108.     }  
  109.   
  110.     /**  
  111.      * 返回渐变的colors数组  
  112.      *   
  113.      * @return  
  114.      */  
  115.     public Color[] getGradientColors() {  
  116.         Color[] colors = new Color[thumbs.size()];  
  117.         int i = 0;  
  118.         for (Thumb t : thumbs) {  
  119.             colors[i] = t.getColor();  
  120.             ++i;  
  121.         }  
  122.   
  123.         return colors;  
  124.     }  
  125.   
  126.     /**  
  127.      * 利用指定圆的圆心和半径和当前的辐射渐变数据,计算相对于指定圆的焦点  
  128.      *   
  129.      * @param center  
  130.      *        圆心  
  131.      * @param radius  
  132.      *        半径  
  133.      * @return 返回相对于指定圆的焦点  
  134.      */  
  135.     public Point2D calculateFocus(Point2D center, double radius) {  
  136.         Point2D curCenter = new Point2D.Double(radialCircle.getCenterX(), radialCircle.getCenterY());  
  137.         double curRadius = radialCircle.getWidth() / 2;  
  138.         double curFocusLen = GeometryUtil.distanceOfPoints(curCenter, focusPoint);  
  139.   
  140.         double newFocusLen = radius * curFocusLen / curRadius;  
  141.         Point2D newFocusPoint = GeometryUtil.extentPoint(curCenter, focusPoint, newFocusLen);  
  142.         // 先移回原点,再移动到center的位置  
  143.         newFocusPoint.setLocation(center.getX() - curCenter.getX(),  
  144.             center.getY() - curCenter.getY());  
  145.   
  146.         return newFocusPoint;  
  147.     }  
  148.   
  149.     public GradientGenerator() {  
  150.         setFocusable(true); // 为了能接收键盘按键事件  
  151.         afterResized();  
  152.         resetThumbs(new float[] { 0.0f, 0.5f, 1.0f }, new Color[] { Color.BLACK, Color.BLUE,  
  153.                 new Color(255, 255, 255, 220) });  
  154.         handleEvents();  
  155.   
  156.         setBackground(Color.DARK_GRAY);  
  157.     }  
  158.   
  159.     // 事件处理  
  160.     private void handleEvents() {  
  161.         this.addMouseListener(new MouseAdapter() {  
  162.             @Override  
  163.             public void mousePressed(MouseEvent e) {  
  164.                 int x = e.getX();  
  165.                 int y = e.getY();  
  166.                 pressedPoint.setLocation(x, y);  
  167.   
  168.                 // 得到被选中的Thumb  
  169.                 for (Thumb t : thumbs) {  
  170.                     if (t.contains(x, y)) {  
  171.                         t.setSelected(true);  
  172.                         selectedThumb = t;  
  173.                         break;  
  174.                     }  
  175.                 }  
  176.                 repaint();  
  177.             }  
  178.   
  179.             @Override  
  180.             public void mouseReleased(MouseEvent e) {  
  181.                 for (Thumb t : thumbs) {  
  182.                     t.setSelected(false);  
  183.                     selectedThumb = null;  
  184.                 }  
  185.                 repaint();  
  186.             }  
  187.   
  188.             @Override  
  189.             public void mouseClicked(MouseEvent e) {  
  190.                 int x = e.getX();  
  191.                 int y = e.getY();  
  192.                 // 左键双击  
  193.                 if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {  
  194.                     // 如果在thumbs里面,则弹出颜色选择器  
  195.                     for (Thumb t : thumbs) {  
  196.                         if (t.contains(x, y)) {  
  197.                             changeThumbColor(t);  
  198.                             repaint();  
  199.                             return;  
  200.                         }  
  201.                     }  
  202.   
  203.                     // 如果不在thumbs里,而在thumbs的区域里,则增加一个thumb  
  204.                     if (thumbsRect.contains(x, y)) {  
  205.                         insertThumbAt(x);  
  206.                         repaint();  
  207.                         return;  
  208.                     }  
  209.   
  210.                     // 修改focus的位置  
  211.                     if (radialRect.contains(x, y)) {  
  212.                         changeFocusPoint(new Point2D.Float(x, y));  
  213.                         repaint();  
  214.                         return;  
  215.                     }  
  216.   
  217.                     // 在Linear rect里面,修改cycle method  
  218.                     if (linearRect.contains(x, y)) {  
  219.                         changeCycleMethod();  
  220.                         repaint();  
  221.                         return;  
  222.                     }  
  223.                 } else if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 2) {  
  224.                     // 右键双击  
  225.                     removeThumbAt(x, y);  
  226.                     return;  
  227.                 }  
  228.             }  
  229.         });  
  230.   
  231.         this.addMouseMotionListener(new MouseMotionAdapter() {  
  232.             @Override  
  233.             public void mouseDragged(MouseEvent e) {  
  234.                 // 拖动滑块  
  235.                 if (selectedThumb != null) {  
  236.                     int deltaX = e.getX() - (int) (selectedThumb.getX());  
  237.                     int x = selectedThumb.getX() + deltaX;  
  238.   
  239.                     // 不能超过边界  
  240.                     int maxRight = (int) (padding.left + linearRect.getWidth());  
  241.                     if (x < padding.left || x > maxRight) { return; }  
  242.   
  243.                     int index = thumbs.indexOf(selectedThumb);  
  244.                     int prevX = Integer.MIN_VALUE;  
  245.                     int nextX = Integer.MAX_VALUE;  
  246.                     // 只能在前一个和后一个之间移动  
  247.                     if (index - 1 >= 0) {  
  248.                         prevX = (int) (thumbs.get(index - 1).getX());  
  249.                     }  
  250.   
  251.                     if (index + 1 < thumbs.size()) {  
  252.                         nextX = (int) (thumbs.get(index + 1).getX());  
  253.                     }  
  254.   
  255.                     if (x > prevX && x < nextX) {  
  256.                         selectedThumb.setX(x);  
  257.                         repaint();  
  258.                     }  
  259.                     return;  
  260.                 } else if (radialRect.contains(e.getX(), e.getY())) {  
  261.                     int deltaX = (int) (e.getX() - pressedPoint.getX());  
  262.                     int deltaY = (int) (e.getY() - pressedPoint.getY());  
  263.                     focusPoint.setLocation(focusPoint.getX() + deltaX, focusPoint.getY() + deltaY);  
  264.                     pressedPoint.setLocation(e.getX(), e.getY());  
  265.                     repaint();  
  266.                 }  
  267.   
  268.             }  
  269.         });  
  270.   
  271.         this.addKeyListener(new KeyAdapter() {  
  272.             @Override  
  273.             public void keyReleased(KeyEvent e) {  
  274.                 switch (e.getKeyCode()) {  
  275.                 case KeyEvent.VK_F:  
  276.                     showCircle = !showCircle;  
  277.                     break;  
  278.                 case KeyEvent.VK_C:  
  279.                     changeFocusPoint(radialCircle.getCenterX(), radialCircle.getCenterY());  
  280.                     break;  
  281.                 }  
  282.                 repaint();  
  283.             }  
  284.         });  
  285.     }  
  286.   
  287.     // 执行监听器的事件  
  288.     public void fireChangeEvent() {  
  289.         for (ChangeListener l : changeListeners) {  
  290.             l.stateChanged(new ChangeEvent(this));  
  291.         }  
  292.     }  
  293.   
  294.     // 改变超出渐变区的颜色渐变方式  
  295.     public void changeCycleMethod() {  
  296.         changeCycleMethod(cycleMethod);  
  297.     }  
  298.   
  299.     public void changeCycleMethod(MultipleGradientPaint.CycleMethod cycleMethod) {  
  300.         switch (cycleMethod) {  
  301.         case NO_CYCLE:  
  302.             this.cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;  
  303.             break;  
  304.         case REFLECT:  
  305.             this.cycleMethod = MultipleGradientPaint.CycleMethod.REPEAT;  
  306.             break;  
  307.         case REPEAT:  
  308.             this.cycleMethod = MultipleGradientPaint.CycleMethod.NO_CYCLE;  
  309.             break;  
  310.         }  
  311.     }  
  312.   
  313.     @Override  
  314.     protected void paintComponent(Graphics g) {  
  315.         super.paintComponent(g);  
  316.         Graphics2D g2d = (Graphics2D) g;  
  317.         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
  318.   
  319.         drawLinearRect(g2d);  
  320.         drawThumbsRect(g2d);  
  321.         drawRadialRect(g2d);  
  322.     }  
  323.   
  324.     // 绘制fraction按钮所在区域  
  325.     private void drawThumbsRect(Graphics2D g2d) {  
  326.         g2d.setColor(new Color(255, 255, 255, 40));  
  327.         g2d.fill(thumbsRect);  
  328.   
  329.         // 绘制fraction按钮  
  330.         for (Thumb t : thumbs) {  
  331.             t.paint(g2d);  
  332.         }  
  333.     }  
  334.   
  335.     private void drawLinearRect(Graphics2D g2d) {  
  336.         // 绘制线性渐变区域  
  337.         float sx = (float) linearRect.getX();  
  338.         float sy = (float) linearRect.getY();  
  339.         float ex = (int) (sx + linearRect.getWidth());  
  340.         float ey = sy;  
  341.         float[] fractions = getGradientFractions();  
  342.         Color[] colors = getGradientColors();  
  343.         Paint p = new LinearGradientPaint(sx, sy, ex, ey, fractions, colors, cycleMethod);  
  344.   
  345.         TransparentPainter.paint(g2d, linearRect);  
  346.         g2d.setPaint(p);  
  347.         g2d.fill(linearRect);  
  348.     }  
  349.   
  350.     // 绘制辐射渐变区  
  351.     private void drawRadialRect(Graphics2D g2d) {  
  352.         float cx = (float) radialCircle.getCenterX();  
  353.         float cy = (float) radialCircle.getCenterY();  
  354.         float fx = (float) focusPoint.getX();  
  355.         float fy = (float) focusPoint.getY();  
  356.         float radius = (float) radialCircle.getWidth() / 2;  
  357.         float[] fractions = getGradientFractions();  
  358.         Color[] colors = getGradientColors();  
  359.   
  360.         TransparentPainter.paint(g2d, radialRect);  
  361.   
  362.         Paint p = new RadialGradientPaint(cx, cy, radius, fx, fy, fractions, colors, cycleMethod);  
  363.         g2d.setPaint(p);  
  364.         g2d.fill(radialRect);  
  365.   
  366.         if (showCircle) {  
  367.             // 绘制辐射渐变的圆  
  368.             g2d.setPaint(Color.BLACK);  
  369.             g2d.draw(radialCircle);  
  370.         }  
  371.     }  
  372.   
  373.     // 最少需要两个渐变值,所以开始就创建两个fraction  
  374.     public void resetThumbs(float[] fractions, Color[] colors) {  
  375.         if (fractions == null || colors == null) { throw new NullPointerException(); }  
  376.         if (fractions.length != colors.length) { throw new IllegalArgumentException(  
  377.             "Fractions 和 Colors 参数个数不等"); }  
  378.   
  379.         int x = (int) thumbsRect.getX();  
  380.         int w = (int) thumbsRect.getWidth();  
  381.         for (int i = 0; i < fractions.length; ++i) {  
  382.             insertThumbAt(x + (int) (w * fractions[i]), colors[i]);  
  383.         }  
  384.     }  
  385.   
  386.     // 在指定的水平位置插入Fraction按钮  
  387.     private void insertThumbAt(int x) {  
  388.         insertThumbAt(x, Color.BLUE);  
  389.     }  
  390.   
  391.     private void insertThumbAt(int x, Color color) {  
  392.         int index = 0;  
  393.         for (Thumb t : thumbs) {  
  394.             if (x > t.getX()) {  
  395.                 index++;  
  396.             }  
  397.         }  
  398.   
  399.         int y = (int) (padding.top + linearRect.getHeight());  
  400.         thumbs.add(index, new Thumb(x, y, color));  
  401.   
  402.         fireChangeEvent();  
  403.     }  
  404.   
  405.     public void removeThumbAt(int x, int y) {  
  406.         for (Thumb t : thumbs) {  
  407.             if (t.contains(x, y)) {  
  408.                 if (thumbs.size() > 2) {  
  409.                     thumbs.remove(t);  
  410.                     fireChangeEvent();  
  411.                     break;  
  412.                 }  
  413.             }  
  414.         }  
  415.     }  
  416.   
  417.     private void changeThumbColor(Thumb thumb) {  
  418.         // 弹出颜色选择器  
  419.         Color newColor = ColorChooser.chooseColor(this, thumb.getColor());  
  420.         if (newColor != null) {  
  421.             thumb.setColor(newColor);  
  422.             fireChangeEvent();  
  423.         }  
  424.     }  
  425.   
  426.     // 改变焦点的位置  
  427.     public void changeFocusPoint(double x, double y) {  
  428.         focusPoint.setLocation(x, y);  
  429.         fireChangeEvent();  
  430.     }  
  431.   
  432.     private void changeFocusPoint(Point2D focusPoint) {  
  433.         changeFocusPoint(focusPoint.getX(), focusPoint.getY());  
  434.     }  
  435.   
  436.     // 当panel的大小改变时,再次调用此函数更新显示区域  
  437.     private void afterResized() {  
  438.         // ////////////////////////////////////////  
  439.         // padding-top  
  440.         // linear gradient area  
  441.         // thumbs area  
  442.         // padding = padding top  
  443.         // radial gradient area  
  444.         // padding-bottom  
  445.         // ///////////////////////////////////////  
  446.   
  447.         // 线性渐变显示区域  
  448.         int x = padding.left;  
  449.         int y = padding.top;  
  450.         int w = width - padding.left - padding.right;  
  451.         int h = linearRectHeight;  
  452.         linearRect.setRect(x, y, w, h);  
  453.   
  454.         // Fraction按钮所在区域  
  455.         y += linearRectHeight;  
  456.         h = thumbRectHeight;  
  457.         thumbsRect.setRect(x, y, w, h);  
  458.   
  459.         // 辐射渐变显示区域  
  460.         y = padding.top + linearRectHeight + thumbRectHeight + padding.top;  
  461.         h = radialRectHeight;  
  462.         h = Math.min(w, h);  
  463.         x = (width - w) / 2;  
  464.         radialRect.setRect(x, y, w, h);  
  465.   
  466.         // 中心点和焦点  
  467.         int cx = x + w / 2;  
  468.         int cy = y + h / 2;  
  469.         int radius = 100;  
  470.         focusPoint.setLocation(cx, cy);  
  471.         radialCircle.setFrame(cx - radius, cy - radius, radius + radius, radius + radius);  
  472.   
  473.         repaint();  
  474.     }  
  475.   
  476.     @Override  
  477.     public Dimension getMinimumSize() {  
  478.         return new Dimension(width, height);  
  479.     }  
  480.   
  481.     @Override  
  482.     public Dimension getMaximumSize() {  
  483.         return new Dimension(width, height);  
  484.     }  
  485.   
  486.     @Override  
  487.     public Dimension getPreferredSize() {  
  488.         return new Dimension(width, height);  
  489.     }  
  490.   
  491.     private static void createGuiAndShow() {  
  492.         JFrame frame = new JFrame("Gradient Generator");  
  493.         JPanel panel = new JPanel();  
  494.         panel.add(new GradientGenerator());  
  495.         frame.setContentPane(new GradientGenerator());  
  496.   
  497.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  498.         frame.pack(); // 使用此函数后always on top就不起作用了  
  499.         frame.setResizable(false);  
  500.         frame.setLocationRelativeTo(null);  
  501.         frame.setAlwaysOnTop(true);  
  502.         frame.setVisible(true);  
  503.     }  
  504.   
  505.     public static void main(String[] args) {  
  506.         createGuiAndShow();  
  507.     }  
  508. }  
  509.   
  510. class Thumb {  
  511.     private int x;  
  512.     private int y;  
  513.     private int width = 16;  
  514.     private int height = 20;  
  515.     private Color color;  
  516.     private boolean selected;  
  517.   
  518.     private GeneralPath outerPath;  
  519.     private GeneralPath innerPath;  
  520.   
  521.     public Thumb(int x, int y, Color color) {  
  522.         setXY(x, y);  
  523.         this.color = color;  
  524.     }  
  525.   
  526.     public int getX() {  
  527.         return x;  
  528.     }  
  529.   
  530.     public void setX(int x) {  
  531.         setXY(x, y);  
  532.     }  
  533.   
  534.     public int getY() {  
  535.         return y;  
  536.     }  
  537.   
  538.     public void setY(int y) {  
  539.         setXY(x, y);  
  540.     }  
  541.   
  542.     public int getWidth() {  
  543.         return width;  
  544.     }  
  545.   
  546.     public void setWidth(int width) {  
  547.         setWidthHeight(width, height);  
  548.     }  
  549.   
  550.     public int getHeight() {  
  551.         return height;  
  552.     }  
  553.   
  554.     public void setHeight(int height) {  
  555.         setWidthHeight(width, height);  
  556.     }  
  557.   
  558.     public Color getColor() {  
  559.         return color;  
  560.     }  
  561.   
  562.     public void setColor(Color color) {  
  563.         this.color = color;  
  564.     }  
  565.   
  566.     public boolean isSelected() {  
  567.         return selected;  
  568.     }  
  569.   
  570.     public void setSelected(boolean selected) {  
  571.         this.selected = selected;  
  572.     }  
  573.   
  574.     public boolean contains(int x, int y) {  
  575.         return outerPath.contains(x, y);  
  576.     }  
  577.   
  578.     public void setXY(int x, int y) {  
  579.         this.x = x;  
  580.         this.y = y;  
  581.         createPaths();  
  582.     }  
  583.   
  584.     public void setWidthHeight(int width, int height) {  
  585.         this.width = width;  
  586.         this.height = height;  
  587.         createPaths();  
  588.     }  
  589.   
  590.     private float[] fractions = new float[] { 0.0f, 0.5f, 1.0f };  
  591.     private Color[] colors = new Color[] { Color.ORANGE, Color.BLACK, Color.ORANGE.brighter() };  
  592.   
  593.     public void paint(Graphics2D g2d) {  
  594.         // 绘制大三角形按钮  
  595.         // Paint p = new GradientPaint(x, y, selected ? color.darker() : color,  
  596.         // x, y + height, Color.ORANGE);  
  597.         Paint p = new LinearGradientPaint(x - width, y, x + width / 4, y, fractions, colors);  
  598.         g2d.setPaint(p);  
  599.         g2d.fill(outerPath);  
  600.   
  601.         // 绘制小三角形按钮  
  602.         g2d.setColor(color);  
  603.         g2d.fill(innerPath);  
  604.     }  
  605.   
  606.     // 创建按钮的形状  
  607.     private void createPaths() {  
  608.         outerPath = new GeneralPath();  
  609.         outerPath.moveTo(x, y);  
  610.         outerPath.lineTo(x + width / 2, y + height);  
  611.         outerPath.lineTo(x - width / 2, y + height);  
  612.         outerPath.closePath();  
  613.   
  614.         innerPath = new GeneralPath();  
  615.         innerPath.moveTo(x, y + height / 2);  
  616.         innerPath.lineTo(x + width / 4, y + height);  
  617.         innerPath.lineTo(x - width / 4, y + height);  
  618.         innerPath.closePath();  
  619.     }  
  620. }  


 

[html] view plain copy
 
  1. package gradient;  
  2.   
  3. import java.awt.AWTEvent;  
  4. import java.awt.BorderLayout;  
  5. import java.awt.Color;  
  6. import java.awt.Component;  
  7. import java.awt.Dimension;  
  8. import java.awt.Graphics;  
  9. import java.awt.Graphics2D;  
  10. import java.awt.Insets;  
  11. import java.awt.RenderingHints;  
  12. import java.awt.Toolkit;  
  13. import java.awt.event.AWTEventListener;  
  14. import java.awt.event.KeyEvent;  
  15. import java.awt.event.MouseAdapter;  
  16. import java.awt.event.MouseEvent;  
  17. import java.awt.event.WindowAdapter;  
  18. import java.awt.event.WindowEvent;  
  19. import java.awt.geom.Rectangle2D;  
  20. import java.awt.image.BufferedImage;  
  21. import java.io.File;  
  22. import java.io.FileNotFoundException;  
  23. import java.util.ArrayList;  
  24. import java.util.List;  
  25. import java.util.Scanner;  
  26.   
  27. import javax.swing.JComponent;  
  28. import javax.swing.JDialog;  
  29. import javax.swing.JPanel;  
  30. import javax.swing.JSlider;  
  31. import javax.swing.event.ChangeEvent;  
  32. import javax.swing.event.ChangeListener;  
  33.   
  34. /**  
  35.  * 创建一个模态的颜色选择对话框,可以加载用户预先定义存储好的颜色.  
  36.  *   
  37.  * @author Biao  
  38.  *   
  39.  */  
  40. @SuppressWarnings("serial")  
  41. public class ColorChooser extends JDialog {  
  42.     private static ColorChooser instance = new ColorChooser();  
  43.     private ColorPanel colorPanel = new ColorPanel();  
  44.     private Color color;  
  45.   
  46.     public static Color chooseColor(JComponent ower, Color defaultColor) {  
  47.         instance.color = defaultColor;  
  48.         instance.colorPanel.startSelect(defaultColor);  
  49.   
  50.         instance.pack();  
  51.         instance.setLocationRelativeTo(ower);  
  52.         instance.setVisible(true);  
  53.   
  54.         return instance.color;  
  55.     }  
  56.   
  57.     private ColorChooser() {  
  58.         setTitle("Choose a color");  
  59.         setModal(true);  
  60.         setResizable(false);  
  61.         setBackground(Color.DARK_GRAY);  
  62.         getContentPane().add(colorPanel, BorderLayout.CENTER);  
  63.   
  64.         this.addWindowListener(new WindowAdapter() {  
  65.             @Override  
  66.             public void windowClosing(WindowEvent e) {  
  67.                 gotoHell(color);  
  68.             }  
  69.         });  
  70.   
  71.         colorPanel.addChangeListener(new ChangeListener() {  
  72.             @Override  
  73.             public void stateChanged(ChangeEvent e) {  
  74.                 Color c = colorPanel.getColor();  
  75.                 if (colorPanel.isDoubleClickSelection()) {  
  76.                     gotoHell(c);  
  77.                 }  
  78.   
  79.                 int r = c.getRed();  
  80.                 int g = c.getGreen();  
  81.                 int b = c.getBlue();  
  82.                 int a = c.getAlpha();  
  83.   
  84.                 String hex = ColorPanel.colorToHexString(new Color(r, g, b, a));  
  85.                 String title = String.format("RGBA(%d,%d,%d,%d) Hex(%s)", r, g, b, a, hex);  
  86.                 setTitle(title);  
  87.             }  
  88.         });  
  89.   
  90.         // 处理JDialog所有子组件的按键事件  
  91.         // 按下回车使用选择的颜色,按下Esc返回默认传进来的颜色  
  92.         Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {  
  93.             @Override  
  94.             public void eventDispatched(AWTEvent event) {  
  95.                 KeyEvent ke = (KeyEvent) event;  
  96.   
  97.                 if (ke.getID() == KeyEvent.KEY_PRESSED) {  
  98.                     if (event.getSource() instanceof Component) {  
  99.                         Component com = (Component) event.getSource();  
  100.                         if (ke.getKeyCode() == KeyEvent.VK_ESCAPE && hasChild(com)) {  
  101.                             gotoHell(color); // 取消时返回默认的颜色  
  102.                         } else if (ke.getKeyCode() == KeyEvent.VK_ENTER && hasChild(com)) {  
  103.                             gotoHell(colorPanel.getColor());  
  104.                         }  
  105.                     }  
  106.                 }  
  107.             }  
  108.         }, AWTEvent.KEY_EVENT_MASK);  
  109.     }  
  110.   
  111.     // 是否包含了组件  
  112.     public boolean hasChild(Component c) {  
  113.         for (Component parent = c; parent != null; parent = parent.getParent()) {  
  114.             if (parent == this) { return true; }  
  115.         }  
  116.         return false;  
  117.     }  
  118.   
  119.     // 隐藏颜色选择对话框  
  120.     public void gotoHell(Color c) {  
  121.         color = (c == null) ? color : c;  
  122.         setVisible(false);  
  123.     }  
  124. }  
  125.   
  126. @SuppressWarnings("serial")  
  127. class ColorPanel extends JPanel {  
  128.     final static private int columnSize = 21; // 每行最多显示21个颜色  
  129.     final static private int sliderHeight = 20; // Slider的高度  
  130.     final static private int previewHeight = 20; // 预览区的高度  
  131.     final static private int colorRectWidth = 20; // 颜色小方块的宽度  
  132.     final static private int colorRectHeight = 20;// 颜色小方块的高度  
  133.   
  134.     private int width = 520; // Color panel的尺寸  
  135.     private int height = 340;  
  136.     private Insets padding = new Insets(10, 10, 0, 10); // 边距  
  137.   
  138.     private int margin = padding.top;  
  139.     private Color color = Color.WHITE;  
  140.     private List<Color> storedColors = new ArrayList<Color>(); // 用户存储的颜色  
  141.     private List<Color> defaultColors = new ArrayList<Color>(); // 使用算法生成的默认颜色  
  142.     private Rectangle2D previewRect = new Rectangle2D.Float(); // 预览区域  
  143.     private Rectangle2D colorsImageRect = new Rectangle2D.Double(); // 显示颜色的区域  
  144.     private BufferedImage colorsImage; // 需要使用颜色信息来创建确定大小  
  145.   
  146.     // 调节rgba的slider  
  147.     private JSlider redSlider = new JSlider(0, 255, 255);  
  148.     private JSlider greenSlider = new JSlider(0, 255, 255);  
  149.     private JSlider blueSlider = new JSlider(0, 255, 255);  
  150.     private JSlider alphaSlider = new JSlider(0, 255, 255);  
  151.   
  152.     // 双击时如果选中颜色,则选择完成  
  153.     private boolean doubleClickSelection = false;  
  154.     private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>();  
  155.   
  156.     public ColorPanel() {  
  157.         // 创建颜色和显示颜色的小方块缓冲图像  
  158.         prepareColors();  
  159.         prepareColorsImage();  
  160.         // 窗口的大小需要用color buffer image的大小来确定,所以必须在这里调用  
  161.         prepareSize();  
  162.   
  163.         preparePreview();  
  164.         prepareSliders();  
  165.   
  166.         this.addMouseListener(new MouseAdapter() {  
  167.             @Override  
  168.             public void mouseClicked(MouseEvent e) {  
  169.                 int x = e.getX();  
  170.                 int y = e.getY();  
  171.                 Color c = getColorAt(x, y);  
  172.   
  173.                 if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 1) {  
  174.                     // 单击时设置选中的颜色  
  175.                     if (c != null) {  
  176.                         setColor(c);  
  177.                         fireStateChanged();  
  178.                     }  
  179.                 } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {  
  180.                     // 双击时返回选中的颜色,隐藏颜色选取窗口  
  181.                     if (c != null || previewRect.contains(x, y)) {  
  182.                         setDoubleClickSelection(true);  
  183.                         fireStateChanged();  
  184.                     }  
  185.                 }  
  186.             }  
  187.         });  
  188.   
  189.         redSlider.addChangeListener(new ChangeListener() {  
  190.             @Override  
  191.             public void stateChanged(ChangeEvent e) {  
  192.                 setR(redSlider.getValue());  
  193.                 fireStateChanged();  
  194.             }  
  195.         });  
  196.   
  197.         greenSlider.addChangeListener(new ChangeListener() {  
  198.             @Override  
  199.             public void stateChanged(ChangeEvent e) {  
  200.                 setG(greenSlider.getValue());  
  201.                 fireStateChanged();  
  202.             }  
  203.         });  
  204.   
  205.         blueSlider.addChangeListener(new ChangeListener() {  
  206.             @Override  
  207.             public void stateChanged(ChangeEvent e) {  
  208.                 setB(blueSlider.getValue());  
  209.                 fireStateChanged();  
  210.             }  
  211.         });  
  212.   
  213.         alphaSlider.addChangeListener(new ChangeListener() {  
  214.             @Override  
  215.             public void stateChanged(ChangeEvent e) {  
  216.                 setA(alphaSlider.getValue());  
  217.                 fireStateChanged();  
  218.             }  
  219.         });  
  220.     }  
  221.   
  222.     @Override  
  223.     protected void paintComponent(Graphics g) {  
  224.         super.paintComponent(g);  
  225.         setBackground(Color.DARK_GRAY);  
  226.         Graphics2D g2d = (Graphics2D) g;  
  227.         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
  228.   
  229.         // 绘制颜色方块的缓冲图片  
  230.         int x = (int) colorsImageRect.getX();  
  231.         int y = (int) colorsImageRect.getY();  
  232.         int w = (int) colorsImageRect.getWidth();  
  233.         int h = (int) colorsImageRect.getHeight();  
  234.         g2d.drawImage(colorsImage, x, y, w, h, null);  
  235.   
  236.         // 绘制颜色预览  
  237.         TransparentPainter.paint(g2d, previewRect);  
  238.         g2d.setPaint(color);  
  239.         g2d.fill(previewRect);  
  240.     }  
  241.   
  242.     public void startSelect(Color color) {  
  243.         setColor(color);  
  244.         setDoubleClickSelection(false);  
  245.     }  
  246.   
  247.     public boolean isDoubleClickSelection() {  
  248.         return doubleClickSelection;  
  249.     }  
  250.   
  251.     protected void setDoubleClickSelection(boolean doubleClickSelection) {  
  252.         this.doubleClickSelection = doubleClickSelection;  
  253.     }  
  254.   
  255.     // 当属性改变事件发生时,调用监听器并且重绘  
  256.     public void fireStateChanged() {  
  257.         for (ChangeListener l : changeListeners) {  
  258.             l.stateChanged(new ChangeEvent(this));  
  259.         }  
  260.         repaint();  
  261.     }  
  262.   
  263.     public void addChangeListener(ChangeListener l) {  
  264.         changeListeners.add(l);  
  265.     }  
  266.   
  267.     public void removeChangeListener(ChangeListener l) {  
  268.         changeListeners.remove(l);  
  269.     }  
  270.   
  271.     // 选得鼠标选中的颜色  
  272.     public Color getColorAt(int x, int y) {  
  273.         // 如果不在显示颜色的图片中,则返回null  
  274.         if (!colorsImageRect.contains(x, y)) { return null; }  
  275.   
  276.         // 以图片的左上角为原点  
  277.         x -colorsImageRect.getX();  
  278.         y -colorsImageRect.getY();  
  279.   
  280.         if (y <= getHeightOfColorsRect(storedColors)) {  
  281.             int i = y / colorRectHeight * columnSize + x / colorRectWidth;  
  282.             return i >= storedColors.size() ? null : storedColors.get(i);  
  283.         } else {  
  284.             y -getHeightOfColorsRect(storedColors) + margin;  
  285.             int i = y / colorRectHeight * columnSize + x / colorRectWidth;  
  286.             return i >= defaultColors.size() ? null : defaultColors.get(i);  
  287.         }  
  288.     }  
  289.   
  290.     // 返回当前选中的颜色  
  291.     public Color getColor() {  
  292.         return color;  
  293.     }  
  294.   
  295.     // 设置当前颜色  
  296.     public void setColor(Color color) {  
  297.         this.color = (color == null) ? Color.WHITE : color;  
  298.         setSliderValues(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());  
  299.     }  
  300.   
  301.     public void setColor(int r, int g, int b) {  
  302.         this.color = new Color(r, g, b, 255);  
  303.         setSliderValues(r, g, b, 255);  
  304.     }  
  305.   
  306.     public void setColor(int r, int g, int b, int a) {  
  307.         r = clamp(r);  
  308.         g = clamp(g);  
  309.         b = clamp(b);  
  310.         a = clamp(a);  
  311.         this.color = new Color(r, g, b, a);  
  312.         setSliderValues(r, g, b, a);  
  313.     }  
  314.   
  315.     public void setR(int r) {  
  316.         setColor(r, color.getGreen(), color.getBlue(), color.getAlpha());  
  317.     }  
  318.   
  319.     public void setG(int g) {  
  320.         setColor(color.getRed(), g, color.getBlue(), color.getAlpha());  
  321.     }  
  322.   
  323.     public void setB(int b) {  
  324.         setColor(color.getRed(), color.getGreen(), b, color.getAlpha());  
  325.     }  
  326.   
  327.     public void setA(int a) {  
  328.         setColor(color.getRed(), color.getGreen(), color.getBlue(), a);  
  329.     }  
  330.   
  331.     public int clamp(int val) {  
  332.         val = val < 0 ? 0 : val;  
  333.         val = val > 255 ? 255 : val;  
  334.         return val;  
  335.     }  
  336.   
  337.     // 设置slier的值  
  338.     private void setSliderValues(int r, int g, int b, int a) {  
  339.         redSlider.setValue(r);  
  340.         greenSlider.setValue(g);  
  341.         blueSlider.setValue(b);  
  342.         alphaSlider.setValue(a);  
  343.   
  344.         fireStateChanged();  
  345.     }  
  346.   
  347.     /**  
  348.      * 把16进制模式的字符串转化成颜色.  
  349.      *   
  350.      * @param hex  
  351.      *        表示颜色的16进制字符串,格式为#rgb, #rrggbb, #aarrggbb  
  352.      * @return 返回字符串的颜色,如果字符串格式不对,返回null  
  353.      */  
  354.     public static Color parseColorHex(String hex) {  
  355.         // #rgb, #rrggbb, #aarrggbb  
  356.         // 检查长度  
  357.         if (hex == null || hex.length() != 4 && hex.length() != 7 && hex.length() != 9  
  358.                 && hex.charAt(0) != '#') { return null; }  
  359.   
  360.         // 检查字符是否有效  
  361.         for (int i = 1; i < hex.length(); ++i) {  
  362.             char aChar = hex.charAt(i);  
  363.             if (!('0' <= aChar && aChar <= '9') && !('a' <= aChar && aChar <= 'f')  
  364.                     && !('A' <= aChar && aChar <= 'F')) { return null; }  
  365.         }  
  366.   
  367.         if (hex.length() == 4) {  
  368.             // #rgb  
  369.             int r = Integer.valueOf(hex.charAt(1) + "" + hex.charAt(1), 16);  
  370.             int g = Integer.valueOf(hex.charAt(2) + "" + hex.charAt(2), 16);  
  371.             int b = Integer.valueOf(hex.charAt(3) + "" + hex.charAt(3), 16);  
  372.             return new Color(r, g, b);  
  373.         } else if (hex.length() == 7) {  
  374.             // #rrggbb  
  375.             int r = Integer.valueOf(hex.substring(1, 3), 16);  
  376.             int g = Integer.valueOf(hex.substring(3, 5), 16);  
  377.             int b = Integer.valueOf(hex.substring(5, 7), 16);  
  378.             return new Color(r, g, b);  
  379.         } else if (hex.length() == 9) {  
  380.             // #aarrggbb  
  381.             int a = Integer.valueOf(hex.substring(1, 3), 16);  
  382.             int r = Integer.valueOf(hex.substring(3, 5), 16);  
  383.             int g = Integer.valueOf(hex.substring(5, 7), 16);  
  384.             int b = Integer.valueOf(hex.substring(7, 9), 16);  
  385.             return new Color(r, g, b, a);  
  386.         }  
  387.   
  388.         return null;  
  389.     }  
  390.   
  391.     public static char[] hexDight = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',  
  392.             'C', 'D', 'E', 'F' };  
  393.   
  394.     /**  
  395.      * 把颜色的表示转换为16进制表示#rrggbbaa  
  396.      *   
  397.      * @param color  
  398.      * @return 返回颜色的16进制字符串  
  399.      */  
  400.     public static String colorToHexString(Color color) {  
  401.         if (color == null) { return "null"; }  
  402.         int r = color.getRed();  
  403.         int g = color.getGreen();  
  404.         int b = color.getBlue();  
  405.         int a = color.getAlpha();  
  406.   
  407.         StringBuilder sb = new StringBuilder("#");  
  408.         sb.append(hexDight[a >> 4 & 0xF]);  
  409.         sb.append(hexDight[a & 0xF]);  
  410.         sb.append(hexDight[r >> 4 & 0xF]);  
  411.         sb.append(hexDight[r & 0xF]);  
  412.         sb.append(hexDight[g >> 4 & 0xF]);  
  413.         sb.append(hexDight[g & 0xF]);  
  414.         sb.append(hexDight[b >> 4 & 0xF]);  
  415.         sb.append(hexDight[b & 0xF]);  
  416.   
  417.         return sb.toString();  
  418.     }  
  419.   
  420.     private void prepareColors() {  
  421.         // 从文件中读取颜色  
  422.         try {  
  423.             Scanner scanner = new Scanner(new File("resources/colors.txt"));  
  424.             while (scanner.hasNextLine()) {  
  425.                 try {  
  426.                     Color c = parseColorHex(scanner.nextLine().trim());  
  427.                     if (c != null) {  
  428.                         storedColors.add(c);  
  429.                     }  
  430.                 } catch (Exception e) {  
  431.                 }  
  432.             }  
  433.         } catch (FileNotFoundException e) {  
  434.             e.printStackTrace();  
  435.         }  
  436.   
  437.         // 创建一些默认的颜色  
  438.         final float delta = 0.2f;  
  439.         for (float r = 0; r <= 1.0; r += delta) {  
  440.             for (float g = 0; g <= 1.0; g += delta) {  
  441.                 for (float b = 0; b <= 1.0; b += delta) {  
  442.                     defaultColors.add(new Color(r, g, b));  
  443.                 }  
  444.             }  
  445.         }  
  446.     }  
  447.   
  448.     private int getHeightOfColorsRect(List<Color> li) {  
  449.         int row = (int) Math.ceil(li.size() / (float) columnSize);  
  450.   
  451.         return row * colorRectWidth;  
  452.     }  
  453.   
  454.     private void prepareColorsImage() {  
  455.         margin = padding.top;  
  456.         int w = columnSize * colorRectWidth;  
  457.         int h = getHeightOfColorsRect(storedColors) + getHeightOfColorsRect(defaultColors) + margin;  
  458.         int x = 0;  
  459.         int y = 0;  
  460.   
  461.         colorsImageRect.setRect(padding.top, padding.top, w, h);  
  462.         colorsImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);  
  463.         Graphics2D g2d = colorsImage.createGraphics();  
  464.   
  465.         // 绘制用户存储的颜色  
  466.         for (int i = 0; i < storedColors.size(); ++i) {  
  467.             g2d.setPaint(storedColors.get(i));  
  468.             g2d.fillRect(x, y, colorRectWidth, colorRectHeight);  
  469.   
  470.             x += colorRectWidth;  
  471.   
  472.             if ((i + 1) % columnSize == 0) {  
  473.                 x = 0;  
  474.                 y += colorRectHeight;  
  475.             }  
  476.         }  
  477.   
  478.         x = 0;  
  479.         y = getHeightOfColorsRect(storedColors) + margin;  
  480.   
  481.         // 绘制默认的颜色  
  482.         for (int i = 0; i < defaultColors.size(); ++i) {  
  483.             g2d.setPaint(defaultColors.get(i));  
  484.             g2d.fillRect(x, y, colorRectWidth, colorRectHeight);  
  485.   
  486.             x += colorRectWidth;  
  487.   
  488.             if ((i + 1) % columnSize == 0) {  
  489.                 x = 0;  
  490.                 y += colorRectHeight;  
  491.             }  
  492.         }  
  493.     }  
  494.   
  495.     private void prepareSize() {  
  496.         width = padding.left + colorsImage.getWidth() + padding.right;  
  497.         height = padding.top + colorsImage.getHeight() + padding.top + previewHeight + sliderHeight;  
  498.     }  
  499.   
  500.     private void preparePreview() {  
  501.         int x = padding.left;  
  502.         int y = height - sliderHeight - previewHeight;  
  503.         int w = width - padding.left - padding.right;  
  504.         previewRect.setRect(x, y, w, previewHeight);  
  505.     }  
  506.   
  507.     private void prepareSliders() {  
  508.         setLayout(null);  
  509.         int margin = 0; // slider之间的间隔,实际没必须  
  510.         int h = sliderHeight;  
  511.         int w = (width - padding.left - padding.right) / 4;  
  512.         int x = padding.left;  
  513.         int y = height - h + 2;  
  514.   
  515.         redSlider.setBounds(x, y, w, h);  
  516.         x += w + margin;  
  517.         greenSlider.setBounds(x, y, w, h);  
  518.         x += w + margin;  
  519.         blueSlider.setBounds(x, y, w, h);  
  520.         x += w + margin;  
  521.         alphaSlider.setBounds(x, y, w, h);  
  522.   
  523.         add(redSlider);  
  524.         add(greenSlider);  
  525.         add(blueSlider);  
  526.         add(alphaSlider);  
  527.     }  
  528.   
  529.     @Override  
  530.     public Dimension getMinimumSize() {  
  531.         return new Dimension(width, height);  
  532.     }  
  533.   
  534.     @Override  
  535.     public Dimension getMaximumSize() {  
  536.         return new Dimension(width, height);  
  537.     }  
  538.   
  539.     @Override  
  540.     public Dimension getPreferredSize() {  
  541.         return new Dimension(width, height);  
  542.     }  
  543. }  


 

[html] view plain copy
 
  1. package gradient;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Graphics2D;  
  5. import java.awt.geom.Rectangle2D;  
  6.   
  7. /**  
  8.  * 绘制Photoshop中透明色的效果.  
  9.  *   
  10.  * @author Biao  
  11.  *   
  12.  */  
  13. public class TransparentPainter {  
  14.     public static void paint(Graphics2D g2d, Rectangle2D rect) {  
  15.         g2d.setClip(rect);  
  16.         int sx = (int) rect.getX();  
  17.         int sy = (int) rect.getY();  
  18.         int w = (int) rect.getWidth();  
  19.         int h = (int) rect.getHeight();  
  20.   
  21.         Color color = Color.WHITE;  
  22.         Color color1 = Color.WHITE;  
  23.         Color color2 = Color.LIGHT_GRAY;  
  24.         int delta = 10;  
  25.         boolean odd = false;  
  26.         for (int y = sy; y <= h + sy; y += delta) {  
  27.             color = (odd) ? color1 : color2;  
  28.             for (int x = sx; x <= w + sx; x += delta) {  
  29.                 g2d.setPaint(color);  
  30.                 g2d.fillRect(x, y, w, h);  
  31.   
  32.                 color = (color == color1) ? color2 : color1;  
  33.             }  
  34.   
  35.             odd = !odd;  
  36.         }  
  37.         g2d.setClip(null);  
  38.     }  
  39. }  


 

[html] view plain copy
 
  1. package gradient;  
  2. import java.awt.geom.Point2D;  
  3.   
  4. public class GeometryUtil {  
  5.     // 两点之间的距离  
  6.     public static double distanceOfPoints(Point2D p1, Point2D p2) {  
  7.         double disX = p2.getX() - p1.getX();  
  8.         double disY = p2.getY() - p1.getY();  
  9.         double dis = Math.sqrt(disX * disX + disY * disY);  
  10.   
  11.         return dis;  
  12.     }  
  13.   
  14.     // 两点的中点  
  15.     public static Point2D middlePoint(Point2D p1, Point2D p2) {  
  16.         double x = (p1.getX() + p2.getX()) / 2;  
  17.         double y = (p1.getY() + p2.getY()) / 2;  
  18.   
  19.         return new Point2D.Double(x, y);  
  20.     }  
  21.   
  22.     // 在两点所在直线上,以从startPoint到endPoint为方向,离startPoint的距离disToStartPoint的点  
  23.     public static Point2D extentPoint(Point2D startPoint, Point2D endPoint, double disToStartPoint) {  
  24.         double disX = endPoint.getX() - startPoint.getX();  
  25.         double disY = endPoint.getY() - startPoint.getY();  
  26.         double dis = Math.sqrt(disX * disX + disY * disY);  
  27.         double sin = (endPoint.getY() - startPoint.getY()) / dis;  
  28.         double cos = (endPoint.getX() - startPoint.getX()) / dis;  
  29.         double deltaX = disToStartPoint * cos;  
  30.         double deltaY = disToStartPoint * sin;  
  31.   
  32.         return new Point2D.Double(startPoint.getX() + deltaX, startPoint.getY() + deltaY);  
  33.     }  
  34. }  
posted @ 2016-06-08 13:56  brave-sailor  阅读(1110)  评论(0编辑  收藏  举报