论坛首页 Java企业应用论坛

Swing渐变生成工具

浏览 9569 次
精华帖 (1) :: 良好帖 (17) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-01-05   最后修改:2011-01-06
生成渐变的数据:float[] fractions,Color[] colors数组,计算指定圆的相对焦点位置等。先Show一下,*^o^*。
利用了ChangleListener,第三方程序可以方便的集成调用,只需要使用addChangeListener即可。自定义颜色选择器,可以读取用户预先定义存储的颜色,默认颜色生成算法还没想好(不管了,先在此现丑了,*^o^*)。
前不久写报表的图时一直使用硬代码去不停的调试效果,用了很久也难以做出满意的效果,正好可以在报表设计中集成这个工具实时的看到设计的效果,*^o^*。




















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();
    }
}

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);
    }
}

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);
    }
}

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);
    }
}

  • 大小: 163.8 KB
  • 大小: 200.9 KB
  • 大小: 169.4 KB
  • 大小: 104.3 KB
  • 大小: 175.1 KB
  • 大小: 145.9 KB
  • 大小: 61 KB
  • 大小: 174.7 KB
  • 大小: 69.3 KB
  • 大小: 30.4 KB
   发表时间:2011-01-05  
很不错哦,LZ继续加油
0 请登录后投票
   发表时间:2011-01-06  
确实漂亮,不知道lz的操作系统是Mac不?
0 请登录后投票
   发表时间:2011-01-06  
更新了Fraction按钮的样式,立体感更强一点点,^_^


  • 大小: 152.3 KB
0 请登录后投票
   发表时间:2011-01-06  
onlylau 写道
确实漂亮,不知道lz的操作系统是Mac不?

是Mac,效果比Windows下好一些。
0 请登录后投票
   发表时间:2011-01-06  
兰州可否share下代码?想研究一下。
0 请登录后投票
   发表时间:2011-01-06  
弱弱地问下,这个干啥用的?
0 请登录后投票
   发表时间:2011-01-06  
不错,可否共享一下代码?
0 请登录后投票
   发表时间:2011-01-06  
pikachu 写道
不错,可否共享一下代码?

呵呵,没问题,因为默认颜色生成和算法还没去查相关的资料,所以才没把代码发出来。
既然有人希望看一下,那我就先献丑了。
0 请登录后投票
   发表时间:2011-01-06   最后修改:2011-01-06
忘了提用户预先定义的颜色了(可以重复使用用户自己喜欢的颜色,合适的颜色,这在设计中非常重要)。
保存在resources/colors.txt文件中,每个颜色使用16进制表示,使用HTML中的颜色格式#rgb, #rrggbb, #aarrggbb,
每个颜色值单独占用一行(可以修改ColorChooser.prepareColors函数实现自己喜欢的存储方式).

还可以为颜色选择窗体添加一些功能,如按下s,保存当前选中的颜色到colors.txt中,这个功能还没有去做。

colors.txt的内容,如:
#FF635D49
#ab4D7B20
#FF7321
#BFDD89
#AA6A2D
#9C1594
#00E500
#E2FF55
#D718A5
#BB2100
#D0F15A
#169800
#00DBFF
#00FF00

补充:Fraction按钮没有使用现成的组件如JLabel,JComponent,JPanel等来做,是为了处理拖动时的相关计算方便一点。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics