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

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

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

 
  1. package gradient;
  2. import java.awt.geom.Point2D;
  3. public class GeometryUtil {
  4. // 两点之间的距离
  5. public static double distanceOfPoints(Point2D p1, Point2D p2) {
  6. double disX = p2.getX() - p1.getX();
  7. double disY = p2.getY() - p1.getY();
  8. double dis = Math.sqrt(disX * disX + disY * disY);
  9. return dis;
  10. }
  11. // 两点的中点
  12. public static Point2D middlePoint(Point2D p1, Point2D p2) {
  13. double x = (p1.getX() + p2.getX()) / 2;
  14. double y = (p1.getY() + p2.getY()) / 2;
  15. return new Point2D.Double(x, y);
  16. }
  17. // 在两点所在直线上,以从startPoint到endPoint为方向,离startPoint的距离disToStartPoint的点
  18. public static Point2D extentPoint(Point2D startPoint, Point2D endPoint, double disToStartPoint) {
  19. double disX = endPoint.getX() - startPoint.getX();
  20. double disY = endPoint.getY() - startPoint.getY();
  21. double dis = Math.sqrt(disX * disX + disY * disY);
  22. double sin = (endPoint.getY() - startPoint.getY()) / dis;
  23. double cos = (endPoint.getX() - startPoint.getX()) / dis;
  24. double deltaX = disToStartPoint * cos;
  25. double deltaY = disToStartPoint * sin;
  26. return new Point2D.Double(startPoint.getX() + deltaX, startPoint.getY() + deltaY);
  27. }
  28. }

java实现渐变效果工具的更多相关文章

  1. 细说Java主流日志工具库

    概述 在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息. 在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子. 我们先来逐一了解一下主流日志工具. java.util ...

  2. Java 性能分析工具 , 第 3 部分: Java Mission Control

    引言 本文为 Java 性能分析工具系列文章第三篇,这里将介绍如何使用 Java 任务控制器 Java Mission Control 深入分析 Java 应用程序的性能,为程序开发人员在使用 Jav ...

  3. Java 性能分析工具 , 第 2 部分:Java 内置监控工具

    引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工 ...

  4. HttpTool.java(在java tool util工具类中已存在) 暂保留

    HttpTool.java 该类为java源生态的http 请求工具,不依赖第三方jar包 ,即插即用. package kingtool; import java.io.BufferedReader ...

  5. java keytool证书工具使用小结

    java keytool证书工具使用小结 在Security编程中,有几种典型的密码交换信息文件格式: DER-encoded certificate: .cer, .crt    PEM-encod ...

  6. [刘阳Java]_避开环境配置快速的使用Java的开发工具_第5讲

    我们一般学习Java都应该遵循通过系统的命令工具来编译Java程序,然后对编译好Java程序进行运行,这个是非常好的习惯.但是随着后期学习Java技术的深入我们也得像Java的IDE工具屈服.所以,可 ...

  7. Java的各种工具类

    下面是java的各种工具,包括获取时间和时间比较,检验集合和字符串是否为空和长度大小等等 1 import java.io.BufferedReader; import java.io.File; i ...

  8. Java XML解析工具 dom4j介绍及使用实例

    Java XML解析工具 dom4j介绍及使用实例 dom4j介绍 dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory ...

  9. TDA - Thread Dump Analyzer (Java线程分析工具)

    TDA - Thread Dump Analyzer (Java线程分析工具)http://automationqa.com/forum.php?mod=viewthread&tid=2351 ...

随机推荐

  1. 研究在SAE上搭建最新wordpress

    安装SAE上的wordpress,创建应用选择wordpress模板,安装后是3.4版本 新建一个版本2,下载最新wordpress安装包并解压到版本2中 初步猜想修改地方: 数据库配置:wp-con ...

  2. Maven介绍,包括作用、核心概念、用法、常用命令、扩展及配置

    由浅入深,主要介绍maven的用途.核心概念(Pom.Repositories.Artifact.Build Lifecycle.Goal).用法(Archetype意义及创建各种项目).maven常 ...

  3. jQuery 插件写法

    一.jQuery插件的类型 1. jQuery方法 很大一部分的jQuery插件都是这种类型,由于此类插件是将对象方法封装起来,在jQuery选择器获取jQuery对象过程中进行操作,从而发挥jQue ...

  4. Python中使用中文

    python的中文问题一直是困扰新手的头疼问题,这篇文章将给你详细地讲解一下这方面的知识.当然,几乎可以确定的是,在将来的版本中,python会彻底解决此问题,不用我们这么麻烦了. 先来看看pytho ...

  5. 【C语言】中的版本规范(C89 C99等)

    C语言中的版本 一.相关基础知识 ISO:国际标准化组织(International Organization for Standardization,ISO)简称ISO,是一个全球性的非政府组织,是 ...

  6. 学习Swift -- 析构过程

    析构过程 析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用.析构器用关键字deinit来标示,类似于构造器要用init来标示. 原理 Swift 会自动释放不再需要的实例以释放资源, ...

  7. ExtJS中动态设置TextField的readOnly属性

    第一种方式: textField, 如果知道textField的id = 'textField' 话,就可以利用如下的方法: 则代码如下:Ext.getCmp("textField" ...

  8. Web 研发模式演变

    前不久徐飞写了一篇很好的文章:Web 应用的组件化开发.本文尝试从历史发展角度,说说各种研发模式的优劣. 一.简单明快的早期时代 可称之为 Web 1.0 时代,非常适合创业型小项目,不分前后端,经常 ...

  9. Loading CSS without blocking render

    The principles behind these techniques aren't new. Filament group, for example, have published great ...

  10. Delphi 类成员的默认访问权限(用RTTI检测)

    类的成员,如果没有private.public等显示什么,直接在class下面,没有写访问权限的限定符,这种成员是不是默认的访问权限啊?还是publish的访问权限啊? --------------- ...