锁定老帖子 主题:Swing渐变生成工具
精华帖 (1) :: 良好帖 (17) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-01-05
最后修改:2011-01-06
利用了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); } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-01-05
很不错哦,LZ继续加油
|
|
返回顶楼 | |
发表时间:2011-01-06
确实漂亮,不知道lz的操作系统是Mac不?
|
|
返回顶楼 | |
发表时间:2011-01-06
更新了Fraction按钮的样式,立体感更强一点点,^_^
|
|
返回顶楼 | |
发表时间:2011-01-06
onlylau 写道 确实漂亮,不知道lz的操作系统是Mac不?
是Mac,效果比Windows下好一些。 |
|
返回顶楼 | |
发表时间:2011-01-06
兰州可否share下代码?想研究一下。
|
|
返回顶楼 | |
发表时间:2011-01-06
弱弱地问下,这个干啥用的?
|
|
返回顶楼 | |
发表时间:2011-01-06
不错,可否共享一下代码?
|
|
返回顶楼 | |
发表时间:2011-01-06
pikachu 写道 不错,可否共享一下代码?
呵呵,没问题,因为默认颜色生成和算法还没去查相关的资料,所以才没把代码发出来。 既然有人希望看一下,那我就先献丑了。 |
|
返回顶楼 | |
发表时间: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等来做,是为了处理拖动时的相关计算方便一点。 |
|
返回顶楼 | |