[html] view plain copy
  1. package gradient;
  2.  
  3. import java.awt.Color;
  4. import java.awt.Dimension;
  5. import java.awt.Graphics;
  6. import java.awt.Graphics2D;
  7. import java.awt.Insets;
  8. import java.awt.LinearGradientPaint;
  9. import java.awt.MultipleGradientPaint;
  10. import java.awt.Paint;
  11. import java.awt.RadialGradientPaint;
  12. import java.awt.RenderingHints;
  13. import java.awt.event.KeyAdapter;
  14. import java.awt.event.KeyEvent;
  15. import java.awt.event.MouseAdapter;
  16. import java.awt.event.MouseEvent;
  17. import java.awt.event.MouseMotionAdapter;
  18. import java.awt.geom.Ellipse2D;
  19. import java.awt.geom.GeneralPath;
  20. import java.awt.geom.Point2D;
  21. import java.awt.geom.Rectangle2D;
  22. import java.util.ArrayList;
  23. import java.util.LinkedList;
  24. import java.util.List;
  25.  
  26. import javax.swing.JFrame;
  27. import javax.swing.JPanel;
  28. import javax.swing.event.ChangeEvent;
  29. import javax.swing.event.ChangeListener;
  30.  
  31. /*
  32. 使用方法:
  33. 渐变窗体:
  34. a. 左键双击顶点的linear gradient 渐变区,改变渐变超出范围的重复绘制模式.
  35. b. 左键双击fractions小按钮区,创建添加一个新的fraction按钮.
  36. c. 左键双击fractions小按钮,弹出窗口选择窗口选择颜色.
  37. d. 右键双击fractions小按钮,删除此fraction按钮.
  38. e. 按住fractions小按钮可以拖动它,修改fractions的位置.
  39. f. 左键双击辐射渐变区,改变辐射渐变的焦点(focus)到点击位置.
  40. g. 在辐射渐变区按住左键拖动,改变辐射渐变的焦点.
  41. h. 按下f,显示辐射渐变的圆周,为了方便看到更清楚的数据,默认这圆周是隐藏的.
  42. i. 按下c,恢复辐射渐变的焦点到辐射渐变的圆心,焦点默认是与圆心重合.
  43.  
  44. 颜色选择窗体:
  45. a. 单击某一个颜色,则选中此颜色,并在底部的预览区显示出来.但颜色选择窗口不消失.
  46. b. 双击某一个颜色,则选中此颜色,返回给调用者,颜色选择窗口消失.
  47. c. 按下回车键,返回选中的颜色,颜色选择窗口消失.
  48. d. 按下ESC键,返回传给颜色选择窗体的默认色,颜色选择窗口消失.
  49. e. 下部的JSlider依次调节被选中颜色的red, green, blue, alpha,拖动并实时的在预览区显示出调整后颜色.
  50.  
  51. 第三方程序集成使用方法: 在第三方程序中创建一个GradientGenerator对象,并添加到组件的某一部分,
  52. 并给此gradientGenerator添加上change listener:
  53. gradientGenerator.addChangeListener(new ChangedListener() {
  54. public void stateChanged(ChangeEvent e) {
  55. float[] fractions = gradientGenerator.getFractons();
  56. Color[] colors = gradientGenerator.getColors();
  57. Point2D focus = gradientGenerator.calculateFocus(center, radius);
  58. repaint(); // 使用这里得到的fractions, colors, focus等去绘制第三方程序中的渐变图形
  59. });
  60. 这样,当gradient generator中的数据发生变化时,第三方程序里也会即时的反映出来.
  61.  
  62. 1. 提示,现在Swing支持合建不规则窗体。
  63. 2. 此程序中,除了JSlider,其他的部分都是使用Java2D手动计算绘制出来的。
  64. 基于上面两点,可以自己创建一个统一的JSlider风格,
  65. 然后就可以把整个程序的外观风格做得在所有平台下都是一个样。
  66. */
  67. /**
  68. * *^o^*,本程序一惯还是一惯的作风,LGPL协议,什么版权的废话就不整了,希望修改得效果好的朋友给大家分享一下心得,在此权当扔出块板砖,
  69. * 希望能砸出块暖玉来,嗷呜嗷呜嗷呜.
  70. */
  71. @SuppressWarnings("serial")
  72. public class GradientGenerator extends JPanel {
  73. private int width = 400; // 整个Panel的宽度
  74. private int height = 400; // 整个Panel的高度
  75. private Insets padding = new Insets(10, 10, 10, 10); // 边距
  76.  
  77. private int thumbRectHeight = 20; // Fraction按钮区的高度
  78. private int linearRectHeight = 40; // 线性渐变区域的高度
  79. private int radialRectHeight = 310; // 辐射渐变区域的高度
  80.  
  81. private Ellipse2D radialCircle = new Ellipse2D.Float(); // 辐射渐变的圆周
  82. private Point2D focusPoint = new Point2D.Float(); // 辐射渐变的焦点
  83. private Point2D pressedPoint = new Point2D.Float(); // 鼠标按下时的点
  84. private Rectangle2D linearRect = new Rectangle2D.Float(); // 线性渐变区域
  85. private Rectangle2D thumbsRect = new Rectangle2D.Float(); // Fractions按钮区域
  86. private Rectangle2D radialRect = new Rectangle2D.Float(); // 辐射渐变区域
  87.  
  88. private Thumb selectedThumb = null; // 被选中的Fraction按钮
  89. private List<Thumb> thumbs = new ArrayList<Thumb>(); // Fractions按钮
  90.  
  91. private boolean showCircle = false; // 显示辐射渐变的圆周
  92. private List<ChangeListener> changeListeners = new LinkedList<ChangeListener>();
  93. private MultipleGradientPaint.CycleMethod cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;
  94.  
  95. /**
  96. * 返回渐变的fractions数组
  97. *
  98. * @return
  99. */
  100. public float[] getGradientFractions() {
  101. float[] fractions = new float[thumbs.size()];
  102. int i = 0;
  103. for (Thumb t : thumbs) {
  104. fractions[i] = (float) ((t.getX() - padding.left) / linearRect.getWidth());
  105. ++i;
  106. }
  107. return fractions;
  108. }
  109.  
  110. /**
  111. * 返回渐变的colors数组
  112. *
  113. * @return
  114. */
  115. public Color[] getGradientColors() {
  116. Color[] colors = new Color[thumbs.size()];
  117. int i = 0;
  118. for (Thumb t : thumbs) {
  119. colors[i] = t.getColor();
  120. ++i;
  121. }
  122.  
  123. return colors;
  124. }
  125.  
  126. /**
  127. * 利用指定圆的圆心和半径和当前的辐射渐变数据,计算相对于指定圆的焦点
  128. *
  129. * @param center
  130. * 圆心
  131. * @param radius
  132. * 半径
  133. * @return 返回相对于指定圆的焦点
  134. */
  135. public Point2D calculateFocus(Point2D center, double radius) {
  136. Point2D curCenter = new Point2D.Double(radialCircle.getCenterX(), radialCircle.getCenterY());
  137. double curRadius = radialCircle.getWidth() / 2;
  138. double curFocusLen = GeometryUtil.distanceOfPoints(curCenter, focusPoint);
  139.  
  140. double newFocusLen = radius * curFocusLen / curRadius;
  141. Point2D newFocusPoint = GeometryUtil.extentPoint(curCenter, focusPoint, newFocusLen);
  142. // 先移回原点,再移动到center的位置
  143. newFocusPoint.setLocation(center.getX() - curCenter.getX(),
  144. center.getY() - curCenter.getY());
  145.  
  146. return newFocusPoint;
  147. }
  148.  
  149. public GradientGenerator() {
  150. setFocusable(true); // 为了能接收键盘按键事件
  151. afterResized();
  152. resetThumbs(new float[] { 0.0f, 0.5f, 1.0f }, new Color[] { Color.BLACK, Color.BLUE,
  153. new Color(255, 255, 255, 220) });
  154. handleEvents();
  155.  
  156. setBackground(Color.DARK_GRAY);
  157. }
  158.  
  159. // 事件处理
  160. private void handleEvents() {
  161. this.addMouseListener(new MouseAdapter() {
  162. @Override
  163. public void mousePressed(MouseEvent e) {
  164. int x = e.getX();
  165. int y = e.getY();
  166. pressedPoint.setLocation(x, y);
  167.  
  168. // 得到被选中的Thumb
  169. for (Thumb t : thumbs) {
  170. if (t.contains(x, y)) {
  171. t.setSelected(true);
  172. selectedThumb = t;
  173. break;
  174. }
  175. }
  176. repaint();
  177. }
  178.  
  179. @Override
  180. public void mouseReleased(MouseEvent e) {
  181. for (Thumb t : thumbs) {
  182. t.setSelected(false);
  183. selectedThumb = null;
  184. }
  185. repaint();
  186. }
  187.  
  188. @Override
  189. public void mouseClicked(MouseEvent e) {
  190. int x = e.getX();
  191. int y = e.getY();
  192. // 左键双击
  193. if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
  194. // 如果在thumbs里面,则弹出颜色选择器
  195. for (Thumb t : thumbs) {
  196. if (t.contains(x, y)) {
  197. changeThumbColor(t);
  198. repaint();
  199. return;
  200. }
  201. }
  202.  
  203. // 如果不在thumbs里,而在thumbs的区域里,则增加一个thumb
  204. if (thumbsRect.contains(x, y)) {
  205. insertThumbAt(x);
  206. repaint();
  207. return;
  208. }
  209.  
  210. // 修改focus的位置
  211. if (radialRect.contains(x, y)) {
  212. changeFocusPoint(new Point2D.Float(x, y));
  213. repaint();
  214. return;
  215. }
  216.  
  217. // 在Linear rect里面,修改cycle method
  218. if (linearRect.contains(x, y)) {
  219. changeCycleMethod();
  220. repaint();
  221. return;
  222. }
  223. } else if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 2) {
  224. // 右键双击
  225. removeThumbAt(x, y);
  226. return;
  227. }
  228. }
  229. });
  230.  
  231. this.addMouseMotionListener(new MouseMotionAdapter() {
  232. @Override
  233. public void mouseDragged(MouseEvent e) {
  234. // 拖动滑块
  235. if (selectedThumb != null) {
  236. int deltaX = e.getX() - (int) (selectedThumb.getX());
  237. int x = selectedThumb.getX() + deltaX;
  238.  
  239. // 不能超过边界
  240. int maxRight = (int) (padding.left + linearRect.getWidth());
  241. if (x < padding.left || x > maxRight) { return; }
  242.  
  243. int index = thumbs.indexOf(selectedThumb);
  244. int prevX = Integer.MIN_VALUE;
  245. int nextX = Integer.MAX_VALUE;
  246. // 只能在前一个和后一个之间移动
  247. if (index - 1 >= 0) {
  248. prevX = (int) (thumbs.get(index - 1).getX());
  249. }
  250.  
  251. if (index + 1 < thumbs.size()) {
  252. nextX = (int) (thumbs.get(index + 1).getX());
  253. }
  254.  
  255. if (x > prevX && x < nextX) {
  256. selectedThumb.setX(x);
  257. repaint();
  258. }
  259. return;
  260. } else if (radialRect.contains(e.getX(), e.getY())) {
  261. int deltaX = (int) (e.getX() - pressedPoint.getX());
  262. int deltaY = (int) (e.getY() - pressedPoint.getY());
  263. focusPoint.setLocation(focusPoint.getX() + deltaX, focusPoint.getY() + deltaY);
  264. pressedPoint.setLocation(e.getX(), e.getY());
  265. repaint();
  266. }
  267.  
  268. }
  269. });
  270.  
  271. this.addKeyListener(new KeyAdapter() {
  272. @Override
  273. public void keyReleased(KeyEvent e) {
  274. switch (e.getKeyCode()) {
  275. case KeyEvent.VK_F:
  276. showCircle = !showCircle;
  277. break;
  278. case KeyEvent.VK_C:
  279. changeFocusPoint(radialCircle.getCenterX(), radialCircle.getCenterY());
  280. break;
  281. }
  282. repaint();
  283. }
  284. });
  285. }
  286.  
  287. // 执行监听器的事件
  288. public void fireChangeEvent() {
  289. for (ChangeListener l : changeListeners) {
  290. l.stateChanged(new ChangeEvent(this));
  291. }
  292. }
  293.  
  294. // 改变超出渐变区的颜色渐变方式
  295. public void changeCycleMethod() {
  296. changeCycleMethod(cycleMethod);
  297. }
  298.  
  299. public void changeCycleMethod(MultipleGradientPaint.CycleMethod cycleMethod) {
  300. switch (cycleMethod) {
  301. case NO_CYCLE:
  302. this.cycleMethod = MultipleGradientPaint.CycleMethod.REFLECT;
  303. break;
  304. case REFLECT:
  305. this.cycleMethod = MultipleGradientPaint.CycleMethod.REPEAT;
  306. break;
  307. case REPEAT:
  308. this.cycleMethod = MultipleGradientPaint.CycleMethod.NO_CYCLE;
  309. break;
  310. }
  311. }
  312.  
  313. @Override
  314. protected void paintComponent(Graphics g) {
  315. super.paintComponent(g);
  316. Graphics2D g2d = (Graphics2D) g;
  317. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  318.  
  319. drawLinearRect(g2d);
  320. drawThumbsRect(g2d);
  321. drawRadialRect(g2d);
  322. }
  323.  
  324. // 绘制fraction按钮所在区域
  325. private void drawThumbsRect(Graphics2D g2d) {
  326. g2d.setColor(new Color(255, 255, 255, 40));
  327. g2d.fill(thumbsRect);
  328.  
  329. // 绘制fraction按钮
  330. for (Thumb t : thumbs) {
  331. t.paint(g2d);
  332. }
  333. }
  334.  
  335. private void drawLinearRect(Graphics2D g2d) {
  336. // 绘制线性渐变区域
  337. float sx = (float) linearRect.getX();
  338. float sy = (float) linearRect.getY();
  339. float ex = (int) (sx + linearRect.getWidth());
  340. float ey = sy;
  341. float[] fractions = getGradientFractions();
  342. Color[] colors = getGradientColors();
  343. Paint p = new LinearGradientPaint(sx, sy, ex, ey, fractions, colors, cycleMethod);
  344.  
  345. TransparentPainter.paint(g2d, linearRect);
  346. g2d.setPaint(p);
  347. g2d.fill(linearRect);
  348. }
  349.  
  350. // 绘制辐射渐变区
  351. private void drawRadialRect(Graphics2D g2d) {
  352. float cx = (float) radialCircle.getCenterX();
  353. float cy = (float) radialCircle.getCenterY();
  354. float fx = (float) focusPoint.getX();
  355. float fy = (float) focusPoint.getY();
  356. float radius = (float) radialCircle.getWidth() / 2;
  357. float[] fractions = getGradientFractions();
  358. Color[] colors = getGradientColors();
  359.  
  360. TransparentPainter.paint(g2d, radialRect);
  361.  
  362. Paint p = new RadialGradientPaint(cx, cy, radius, fx, fy, fractions, colors, cycleMethod);
  363. g2d.setPaint(p);
  364. g2d.fill(radialRect);
  365.  
  366. if (showCircle) {
  367. // 绘制辐射渐变的圆
  368. g2d.setPaint(Color.BLACK);
  369. g2d.draw(radialCircle);
  370. }
  371. }
  372.  
  373. // 最少需要两个渐变值,所以开始就创建两个fraction
  374. public void resetThumbs(float[] fractions, Color[] colors) {
  375. if (fractions == null || colors == null) { throw new NullPointerException(); }
  376. if (fractions.length != colors.length) { throw new IllegalArgumentException(
  377. "Fractions 和 Colors 参数个数不等"); }
  378.  
  379. int x = (int) thumbsRect.getX();
  380. int w = (int) thumbsRect.getWidth();
  381. for (int i = 0; i < fractions.length; ++i) {
  382. insertThumbAt(x + (int) (w * fractions[i]), colors[i]);
  383. }
  384. }
  385.  
  386. // 在指定的水平位置插入Fraction按钮
  387. private void insertThumbAt(int x) {
  388. insertThumbAt(x, Color.BLUE);
  389. }
  390.  
  391. private void insertThumbAt(int x, Color color) {
  392. int index = 0;
  393. for (Thumb t : thumbs) {
  394. if (x > t.getX()) {
  395. index++;
  396. }
  397. }
  398.  
  399. int y = (int) (padding.top + linearRect.getHeight());
  400. thumbs.add(index, new Thumb(x, y, color));
  401.  
  402. fireChangeEvent();
  403. }
  404.  
  405. public void removeThumbAt(int x, int y) {
  406. for (Thumb t : thumbs) {
  407. if (t.contains(x, y)) {
  408. if (thumbs.size() > 2) {
  409. thumbs.remove(t);
  410. fireChangeEvent();
  411. break;
  412. }
  413. }
  414. }
  415. }
  416.  
  417. private void changeThumbColor(Thumb thumb) {
  418. // 弹出颜色选择器
  419. Color newColor = ColorChooser.chooseColor(this, thumb.getColor());
  420. if (newColor != null) {
  421. thumb.setColor(newColor);
  422. fireChangeEvent();
  423. }
  424. }
  425.  
  426. // 改变焦点的位置
  427. public void changeFocusPoint(double x, double y) {
  428. focusPoint.setLocation(x, y);
  429. fireChangeEvent();
  430. }
  431.  
  432. private void changeFocusPoint(Point2D focusPoint) {
  433. changeFocusPoint(focusPoint.getX(), focusPoint.getY());
  434. }
  435.  
  436. // 当panel的大小改变时,再次调用此函数更新显示区域
  437. private void afterResized() {
  438. // ////////////////////////////////////////
  439. // padding-top
  440. // linear gradient area
  441. // thumbs area
  442. // padding = padding top
  443. // radial gradient area
  444. // padding-bottom
  445. // ///////////////////////////////////////
  446.  
  447. // 线性渐变显示区域
  448. int x = padding.left;
  449. int y = padding.top;
  450. int w = width - padding.left - padding.right;
  451. int h = linearRectHeight;
  452. linearRect.setRect(x, y, w, h);
  453.  
  454. // Fraction按钮所在区域
  455. y += linearRectHeight;
  456. h = thumbRectHeight;
  457. thumbsRect.setRect(x, y, w, h);
  458.  
  459. // 辐射渐变显示区域
  460. y = padding.top + linearRectHeight + thumbRectHeight + padding.top;
  461. h = radialRectHeight;
  462. h = Math.min(w, h);
  463. x = (width - w) / 2;
  464. radialRect.setRect(x, y, w, h);
  465.  
  466. // 中心点和焦点
  467. int cx = x + w / 2;
  468. int cy = y + h / 2;
  469. int radius = 100;
  470. focusPoint.setLocation(cx, cy);
  471. radialCircle.setFrame(cx - radius, cy - radius, radius + radius, radius + radius);
  472.  
  473. repaint();
  474. }
  475.  
  476. @Override
  477. public Dimension getMinimumSize() {
  478. return new Dimension(width, height);
  479. }
  480.  
  481. @Override
  482. public Dimension getMaximumSize() {
  483. return new Dimension(width, height);
  484. }
  485.  
  486. @Override
  487. public Dimension getPreferredSize() {
  488. return new Dimension(width, height);
  489. }
  490.  
  491. private static void createGuiAndShow() {
  492. JFrame frame = new JFrame("Gradient Generator");
  493. JPanel panel = new JPanel();
  494. panel.add(new GradientGenerator());
  495. frame.setContentPane(new GradientGenerator());
  496.  
  497. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  498. frame.pack(); // 使用此函数后always on top就不起作用了
  499. frame.setResizable(false);
  500. frame.setLocationRelativeTo(null);
  501. frame.setAlwaysOnTop(true);
  502. frame.setVisible(true);
  503. }
  504.  
  505. public static void main(String[] args) {
  506. createGuiAndShow();
  507. }
  508. }
  509.  
  510. class Thumb {
  511. private int x;
  512. private int y;
  513. private int width = 16;
  514. private int height = 20;
  515. private Color color;
  516. private boolean selected;
  517.  
  518. private GeneralPath outerPath;
  519. private GeneralPath innerPath;
  520.  
  521. public Thumb(int x, int y, Color color) {
  522. setXY(x, y);
  523. this.color = color;
  524. }
  525.  
  526. public int getX() {
  527. return x;
  528. }
  529.  
  530. public void setX(int x) {
  531. setXY(x, y);
  532. }
  533.  
  534. public int getY() {
  535. return y;
  536. }
  537.  
  538. public void setY(int y) {
  539. setXY(x, y);
  540. }
  541.  
  542. public int getWidth() {
  543. return width;
  544. }
  545.  
  546. public void setWidth(int width) {
  547. setWidthHeight(width, height);
  548. }
  549.  
  550. public int getHeight() {
  551. return height;
  552. }
  553.  
  554. public void setHeight(int height) {
  555. setWidthHeight(width, height);
  556. }
  557.  
  558. public Color getColor() {
  559. return color;
  560. }
  561.  
  562. public void setColor(Color color) {
  563. this.color = color;
  564. }
  565.  
  566. public boolean isSelected() {
  567. return selected;
  568. }
  569.  
  570. public void setSelected(boolean selected) {
  571. this.selected = selected;
  572. }
  573.  
  574. public boolean contains(int x, int y) {
  575. return outerPath.contains(x, y);
  576. }
  577.  
  578. public void setXY(int x, int y) {
  579. this.x = x;
  580. this.y = y;
  581. createPaths();
  582. }
  583.  
  584. public void setWidthHeight(int width, int height) {
  585. this.width = width;
  586. this.height = height;
  587. createPaths();
  588. }
  589.  
  590. private float[] fractions = new float[] { 0.0f, 0.5f, 1.0f };
  591. private Color[] colors = new Color[] { Color.ORANGE, Color.BLACK, Color.ORANGE.brighter() };
  592.  
  593. public void paint(Graphics2D g2d) {
  594. // 绘制大三角形按钮
  595. // Paint p = new GradientPaint(x, y, selected ? color.darker() : color,
  596. // x, y + height, Color.ORANGE);
  597. Paint p = new LinearGradientPaint(x - width, y, x + width / 4, y, fractions, colors);
  598. g2d.setPaint(p);
  599. g2d.fill(outerPath);
  600.  
  601. // 绘制小三角形按钮
  602. g2d.setColor(color);
  603. g2d.fill(innerPath);
  604. }
  605.  
  606. // 创建按钮的形状
  607. private void createPaths() {
  608. outerPath = new GeneralPath();
  609. outerPath.moveTo(x, y);
  610. outerPath.lineTo(x + width / 2, y + height);
  611. outerPath.lineTo(x - width / 2, y + height);
  612. outerPath.closePath();
  613.  
  614. innerPath = new GeneralPath();
  615. innerPath.moveTo(x, y + height / 2);
  616. innerPath.lineTo(x + width / 4, y + height);
  617. innerPath.lineTo(x - width / 4, y + height);
  618. innerPath.closePath();
  619. }
  620. }
  621.  
  622. [html] view plain copy
  623. package gradient;
  624.  
  625. import java.awt.AWTEvent;
  626. import java.awt.BorderLayout;
  627. import java.awt.Color;
  628. import java.awt.Component;
  629. import java.awt.Dimension;
  630. import java.awt.Graphics;
  631. import java.awt.Graphics2D;
  632. import java.awt.Insets;
  633. import java.awt.RenderingHints;
  634. import java.awt.Toolkit;
  635. import java.awt.event.AWTEventListener;
  636. import java.awt.event.KeyEvent;
  637. import java.awt.event.MouseAdapter;
  638. import java.awt.event.MouseEvent;
  639. import java.awt.event.WindowAdapter;
  640. import java.awt.event.WindowEvent;
  641. import java.awt.geom.Rectangle2D;
  642. import java.awt.image.BufferedImage;
  643. import java.io.File;
  644. import java.io.FileNotFoundException;
  645. import java.util.ArrayList;
  646. import java.util.List;
  647. import java.util.Scanner;
  648.  
  649. import javax.swing.JComponent;
  650. import javax.swing.JDialog;
  651. import javax.swing.JPanel;
  652. import javax.swing.JSlider;
  653. import javax.swing.event.ChangeEvent;
  654. import javax.swing.event.ChangeListener;
  655.  
  656. /**
  657. * 创建一个模态的颜色选择对话框,可以加载用户预先定义存储好的颜色.
  658. *
  659. * @author Biao
  660. *
  661. */
  662. @SuppressWarnings("serial")
  663. public class ColorChooser extends JDialog {
  664. private static ColorChooser instance = new ColorChooser();
  665. private ColorPanel colorPanel = new ColorPanel();
  666. private Color color;
  667.  
  668. public static Color chooseColor(JComponent ower, Color defaultColor) {
  669. instance.color = defaultColor;
  670. instance.colorPanel.startSelect(defaultColor);
  671.  
  672. instance.pack();
  673. instance.setLocationRelativeTo(ower);
  674. instance.setVisible(true);
  675.  
  676. return instance.color;
  677. }
  678.  
  679. private ColorChooser() {
  680. setTitle("Choose a color");
  681. setModal(true);
  682. setResizable(false);
  683. setBackground(Color.DARK_GRAY);
  684. getContentPane().add(colorPanel, BorderLayout.CENTER);
  685.  
  686. this.addWindowListener(new WindowAdapter() {
  687. @Override
  688. public void windowClosing(WindowEvent e) {
  689. gotoHell(color);
  690. }
  691. });
  692.  
  693. colorPanel.addChangeListener(new ChangeListener() {
  694. @Override
  695. public void stateChanged(ChangeEvent e) {
  696. Color c = colorPanel.getColor();
  697. if (colorPanel.isDoubleClickSelection()) {
  698. gotoHell(c);
  699. }
  700.  
  701. int r = c.getRed();
  702. int g = c.getGreen();
  703. int b = c.getBlue();
  704. int a = c.getAlpha();
  705.  
  706. String hex = ColorPanel.colorToHexString(new Color(r, g, b, a));
  707. String title = String.format("RGBA(%d,%d,%d,%d) Hex(%s)", r, g, b, a, hex);
  708. setTitle(title);
  709. }
  710. });
  711.  
  712. // 处理JDialog所有子组件的按键事件
  713. // 按下回车使用选择的颜色,按下Esc返回默认传进来的颜色
  714. Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
  715. @Override
  716. public void eventDispatched(AWTEvent event) {
  717. KeyEvent ke = (KeyEvent) event;
  718.  
  719. if (ke.getID() == KeyEvent.KEY_PRESSED) {
  720. if (event.getSource() instanceof Component) {
  721. Component com = (Component) event.getSource();
  722. if (ke.getKeyCode() == KeyEvent.VK_ESCAPE && hasChild(com)) {
  723. gotoHell(color); // 取消时返回默认的颜色
  724. } else if (ke.getKeyCode() == KeyEvent.VK_ENTER && hasChild(com)) {
  725. gotoHell(colorPanel.getColor());
  726. }
  727. }
  728. }
  729. }
  730. }, AWTEvent.KEY_EVENT_MASK);
  731. }
  732.  
  733. // 是否包含了组件
  734. public boolean hasChild(Component c) {
  735. for (Component parent = c; parent != null; parent = parent.getParent()) {
  736. if (parent == this) { return true; }
  737. }
  738. return false;
  739. }
  740.  
  741. // 隐藏颜色选择对话框
  742. public void gotoHell(Color c) {
  743. color = (c == null) ? color : c;
  744. setVisible(false);
  745. }
  746. }
  747.  
  748. @SuppressWarnings("serial")
  749. class ColorPanel extends JPanel {
  750. final static private int columnSize = 21; // 每行最多显示21个颜色
  751. final static private int sliderHeight = 20; // Slider的高度
  752. final static private int previewHeight = 20; // 预览区的高度
  753. final static private int colorRectWidth = 20; // 颜色小方块的宽度
  754. final static private int colorRectHeight = 20;// 颜色小方块的高度
  755.  
  756. private int width = 520; // Color panel的尺寸
  757. private int height = 340;
  758. private Insets padding = new Insets(10, 10, 0, 10); // 边距
  759.  
  760. private int margin = padding.top;
  761. private Color color = Color.WHITE;
  762. private List<Color> storedColors = new ArrayList<Color>(); // 用户存储的颜色
  763. private List<Color> defaultColors = new ArrayList<Color>(); // 使用算法生成的默认颜色
  764. private Rectangle2D previewRect = new Rectangle2D.Float(); // 预览区域
  765. private Rectangle2D colorsImageRect = new Rectangle2D.Double(); // 显示颜色的区域
  766. private BufferedImage colorsImage; // 需要使用颜色信息来创建确定大小
  767.  
  768. // 调节rgba的slider
  769. private JSlider redSlider = new JSlider(0, 255, 255);
  770. private JSlider greenSlider = new JSlider(0, 255, 255);
  771. private JSlider blueSlider = new JSlider(0, 255, 255);
  772. private JSlider alphaSlider = new JSlider(0, 255, 255);
  773.  
  774. // 双击时如果选中颜色,则选择完成
  775. private boolean doubleClickSelection = false;
  776. private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>();
  777.  
  778. public ColorPanel() {
  779. // 创建颜色和显示颜色的小方块缓冲图像
  780. prepareColors();
  781. prepareColorsImage();
  782. // 窗口的大小需要用color buffer image的大小来确定,所以必须在这里调用
  783. prepareSize();
  784.  
  785. preparePreview();
  786. prepareSliders();
  787.  
  788. this.addMouseListener(new MouseAdapter() {
  789. @Override
  790. public void mouseClicked(MouseEvent e) {
  791. int x = e.getX();
  792. int y = e.getY();
  793. Color c = getColorAt(x, y);
  794.  
  795. if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 1) {
  796. // 单击时设置选中的颜色
  797. if (c != null) {
  798. setColor(c);
  799. fireStateChanged();
  800. }
  801. } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
  802. // 双击时返回选中的颜色,隐藏颜色选取窗口
  803. if (c != null || previewRect.contains(x, y)) {
  804. setDoubleClickSelection(true);
  805. fireStateChanged();
  806. }
  807. }
  808. }
  809. });
  810.  
  811. redSlider.addChangeListener(new ChangeListener() {
  812. @Override
  813. public void stateChanged(ChangeEvent e) {
  814. setR(redSlider.getValue());
  815. fireStateChanged();
  816. }
  817. });
  818.  
  819. greenSlider.addChangeListener(new ChangeListener() {
  820. @Override
  821. public void stateChanged(ChangeEvent e) {
  822. setG(greenSlider.getValue());
  823. fireStateChanged();
  824. }
  825. });
  826.  
  827. blueSlider.addChangeListener(new ChangeListener() {
  828. @Override
  829. public void stateChanged(ChangeEvent e) {
  830. setB(blueSlider.getValue());
  831. fireStateChanged();
  832. }
  833. });
  834.  
  835. alphaSlider.addChangeListener(new ChangeListener() {
  836. @Override
  837. public void stateChanged(ChangeEvent e) {
  838. setA(alphaSlider.getValue());
  839. fireStateChanged();
  840. }
  841. });
  842. }
  843.  
  844. @Override
  845. protected void paintComponent(Graphics g) {
  846. super.paintComponent(g);
  847. setBackground(Color.DARK_GRAY);
  848. Graphics2D g2d = (Graphics2D) g;
  849. g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  850.  
  851. // 绘制颜色方块的缓冲图片
  852. int x = (int) colorsImageRect.getX();
  853. int y = (int) colorsImageRect.getY();
  854. int w = (int) colorsImageRect.getWidth();
  855. int h = (int) colorsImageRect.getHeight();
  856. g2d.drawImage(colorsImage, x, y, w, h, null);
  857.  
  858. // 绘制颜色预览
  859. TransparentPainter.paint(g2d, previewRect);
  860. g2d.setPaint(color);
  861. g2d.fill(previewRect);
  862. }
  863.  
  864. public void startSelect(Color color) {
  865. setColor(color);
  866. setDoubleClickSelection(false);
  867. }
  868.  
  869. public boolean isDoubleClickSelection() {
  870. return doubleClickSelection;
  871. }
  872.  
  873. protected void setDoubleClickSelection(boolean doubleClickSelection) {
  874. this.doubleClickSelection = doubleClickSelection;
  875. }
  876.  
  877. // 当属性改变事件发生时,调用监听器并且重绘
  878. public void fireStateChanged() {
  879. for (ChangeListener l : changeListeners) {
  880. l.stateChanged(new ChangeEvent(this));
  881. }
  882. repaint();
  883. }
  884.  
  885. public void addChangeListener(ChangeListener l) {
  886. changeListeners.add(l);
  887. }
  888.  
  889. public void removeChangeListener(ChangeListener l) {
  890. changeListeners.remove(l);
  891. }
  892.  
  893. // 选得鼠标选中的颜色
  894. public Color getColorAt(int x, int y) {
  895. // 如果不在显示颜色的图片中,则返回null
  896. if (!colorsImageRect.contains(x, y)) { return null; }
  897.  
  898. // 以图片的左上角为原点
  899. x -= colorsImageRect.getX();
  900. y -= colorsImageRect.getY();
  901.  
  902. if (y <= getHeightOfColorsRect(storedColors)) {
  903. int i = y / colorRectHeight * columnSize + x / colorRectWidth;
  904. return i >= storedColors.size() ? null : storedColors.get(i);
  905. } else {
  906. y -= getHeightOfColorsRect(storedColors) + margin;
  907. int i = y / colorRectHeight * columnSize + x / colorRectWidth;
  908. return i >= defaultColors.size() ? null : defaultColors.get(i);
  909. }
  910. }
  911.  
  912. // 返回当前选中的颜色
  913. public Color getColor() {
  914. return color;
  915. }
  916.  
  917. // 设置当前颜色
  918. public void setColor(Color color) {
  919. this.color = (color == null) ? Color.WHITE : color;
  920. setSliderValues(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
  921. }
  922.  
  923. public void setColor(int r, int g, int b) {
  924. this.color = new Color(r, g, b, 255);
  925. setSliderValues(r, g, b, 255);
  926. }
  927.  
  928. public void setColor(int r, int g, int b, int a) {
  929. r = clamp(r);
  930. g = clamp(g);
  931. b = clamp(b);
  932. a = clamp(a);
  933. this.color = new Color(r, g, b, a);
  934. setSliderValues(r, g, b, a);
  935. }
  936.  
  937. public void setR(int r) {
  938. setColor(r, color.getGreen(), color.getBlue(), color.getAlpha());
  939. }
  940.  
  941. public void setG(int g) {
  942. setColor(color.getRed(), g, color.getBlue(), color.getAlpha());
  943. }
  944.  
  945. public void setB(int b) {
  946. setColor(color.getRed(), color.getGreen(), b, color.getAlpha());
  947. }
  948.  
  949. public void setA(int a) {
  950. setColor(color.getRed(), color.getGreen(), color.getBlue(), a);
  951. }
  952.  
  953. public int clamp(int val) {
  954. val = val < 0 ? 0 : val;
  955. val = val > 255 ? 255 : val;
  956. return val;
  957. }
  958.  
  959. // 设置slier的值
  960. private void setSliderValues(int r, int g, int b, int a) {
  961. redSlider.setValue(r);
  962. greenSlider.setValue(g);
  963. blueSlider.setValue(b);
  964. alphaSlider.setValue(a);
  965.  
  966. fireStateChanged();
  967. }
  968.  
  969. /**
  970. * 把16进制模式的字符串转化成颜色.
  971. *
  972. * @param hex
  973. * 表示颜色的16进制字符串,格式为#rgb, #rrggbb, #aarrggbb
  974. * @return 返回字符串的颜色,如果字符串格式不对,返回null
  975. */
  976. public static Color parseColorHex(String hex) {
  977. // #rgb, #rrggbb, #aarrggbb
  978. // 检查长度
  979. if (hex == null || hex.length() != 4 && hex.length() != 7 && hex.length() != 9
  980. && hex.charAt(0) != '#') { return null; }
  981.  
  982. // 检查字符是否有效
  983. for (int i = 1; i < hex.length(); ++i) {
  984. char aChar = hex.charAt(i);
  985. if (!('0' <= aChar && aChar <= '9') && !('a' <= aChar && aChar <= 'f')
  986. && !('A' <= aChar && aChar <= 'F')) { return null; }
  987. }
  988.  
  989. if (hex.length() == 4) {
  990. // #rgb
  991. int r = Integer.valueOf(hex.charAt(1) + "" + hex.charAt(1), 16);
  992. int g = Integer.valueOf(hex.charAt(2) + "" + hex.charAt(2), 16);
  993. int b = Integer.valueOf(hex.charAt(3) + "" + hex.charAt(3), 16);
  994. return new Color(r, g, b);
  995. } else if (hex.length() == 7) {
  996. // #rrggbb
  997. int r = Integer.valueOf(hex.substring(1, 3), 16);
  998. int g = Integer.valueOf(hex.substring(3, 5), 16);
  999. int b = Integer.valueOf(hex.substring(5, 7), 16);
  1000. return new Color(r, g, b);
  1001. } else if (hex.length() == 9) {
  1002. // #aarrggbb
  1003. int a = Integer.valueOf(hex.substring(1, 3), 16);
  1004. int r = Integer.valueOf(hex.substring(3, 5), 16);
  1005. int g = Integer.valueOf(hex.substring(5, 7), 16);
  1006. int b = Integer.valueOf(hex.substring(7, 9), 16);
  1007. return new Color(r, g, b, a);
  1008. }
  1009.  
  1010. return null;
  1011. }
  1012.  
  1013. public static char[] hexDight = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
  1014. 'C', 'D', 'E', 'F' };
  1015.  
  1016. /**
  1017. * 把颜色的表示转换为16进制表示#rrggbbaa
  1018. *
  1019. * @param color
  1020. * @return 返回颜色的16进制字符串
  1021. */
  1022. public static String colorToHexString(Color color) {
  1023. if (color == null) { return "null"; }
  1024. int r = color.getRed();
  1025. int g = color.getGreen();
  1026. int b = color.getBlue();
  1027. int a = color.getAlpha();
  1028.  
  1029. StringBuilder sb = new StringBuilder("#");
  1030. sb.append(hexDight[a >> 4 & 0xF]);
  1031. sb.append(hexDight[a & 0xF]);
  1032. sb.append(hexDight[r >> 4 & 0xF]);
  1033. sb.append(hexDight[r & 0xF]);
  1034. sb.append(hexDight[g >> 4 & 0xF]);
  1035. sb.append(hexDight[g & 0xF]);
  1036. sb.append(hexDight[b >> 4 & 0xF]);
  1037. sb.append(hexDight[b & 0xF]);
  1038.  
  1039. return sb.toString();
  1040. }
  1041.  
  1042. private void prepareColors() {
  1043. // 从文件中读取颜色
  1044. try {
  1045. Scanner scanner = new Scanner(new File("resources/colors.txt"));
  1046. while (scanner.hasNextLine()) {
  1047. try {
  1048. Color c = parseColorHex(scanner.nextLine().trim());
  1049. if (c != null) {
  1050. storedColors.add(c);
  1051. }
  1052. } catch (Exception e) {
  1053. }
  1054. }
  1055. } catch (FileNotFoundException e) {
  1056. e.printStackTrace();
  1057. }
  1058.  
  1059. // 创建一些默认的颜色
  1060. final float delta = 0.2f;
  1061. for (float r = 0; r <= 1.0; r += delta) {
  1062. for (float g = 0; g <= 1.0; g += delta) {
  1063. for (float b = 0; b <= 1.0; b += delta) {
  1064. defaultColors.add(new Color(r, g, b));
  1065. }
  1066. }
  1067. }
  1068. }
  1069.  
  1070. private int getHeightOfColorsRect(List<Color> li) {
  1071. int row = (int) Math.ceil(li.size() / (float) columnSize);
  1072.  
  1073. return row * colorRectWidth;
  1074. }
  1075.  
  1076. private void prepareColorsImage() {
  1077. margin = padding.top;
  1078. int w = columnSize * colorRectWidth;
  1079. int h = getHeightOfColorsRect(storedColors) + getHeightOfColorsRect(defaultColors) + margin;
  1080. int x = 0;
  1081. int y = 0;
  1082.  
  1083. colorsImageRect.setRect(padding.top, padding.top, w, h);
  1084. colorsImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
  1085. Graphics2D g2d = colorsImage.createGraphics();
  1086.  
  1087. // 绘制用户存储的颜色
  1088. for (int i = 0; i < storedColors.size(); ++i) {
  1089. g2d.setPaint(storedColors.get(i));
  1090. g2d.fillRect(x, y, colorRectWidth, colorRectHeight);
  1091.  
  1092. x += colorRectWidth;
  1093.  
  1094. if ((i + 1) % columnSize == 0) {
  1095. x = 0;
  1096. y += colorRectHeight;
  1097. }
  1098. }
  1099.  
  1100. x = 0;
  1101. y = getHeightOfColorsRect(storedColors) + margin;
  1102.  
  1103. // 绘制默认的颜色
  1104. for (int i = 0; i < defaultColors.size(); ++i) {
  1105. g2d.setPaint(defaultColors.get(i));
  1106. g2d.fillRect(x, y, colorRectWidth, colorRectHeight);
  1107.  
  1108. x += colorRectWidth;
  1109.  
  1110. if ((i + 1) % columnSize == 0) {
  1111. x = 0;
  1112. y += colorRectHeight;
  1113. }
  1114. }
  1115. }
  1116.  
  1117. private void prepareSize() {
  1118. width = padding.left + colorsImage.getWidth() + padding.right;
  1119. height = padding.top + colorsImage.getHeight() + padding.top + previewHeight + sliderHeight;
  1120. }
  1121.  
  1122. private void preparePreview() {
  1123. int x = padding.left;
  1124. int y = height - sliderHeight - previewHeight;
  1125. int w = width - padding.left - padding.right;
  1126. previewRect.setRect(x, y, w, previewHeight);
  1127. }
  1128.  
  1129. private void prepareSliders() {
  1130. setLayout(null);
  1131. int margin = 0; // slider之间的间隔,实际没必须
  1132. int h = sliderHeight;
  1133. int w = (width - padding.left - padding.right) / 4;
  1134. int x = padding.left;
  1135. int y = height - h + 2;
  1136.  
  1137. redSlider.setBounds(x, y, w, h);
  1138. x += w + margin;
  1139. greenSlider.setBounds(x, y, w, h);
  1140. x += w + margin;
  1141. blueSlider.setBounds(x, y, w, h);
  1142. x += w + margin;
  1143. alphaSlider.setBounds(x, y, w, h);
  1144.  
  1145. add(redSlider);
  1146. add(greenSlider);
  1147. add(blueSlider);
  1148. add(alphaSlider);
  1149. }
  1150.  
  1151. @Override
  1152. public Dimension getMinimumSize() {
  1153. return new Dimension(width, height);
  1154. }
  1155.  
  1156. @Override
  1157. public Dimension getMaximumSize() {
  1158. return new Dimension(width, height);
  1159. }
  1160.  
  1161. @Override
  1162. public Dimension getPreferredSize() {
  1163. return new Dimension(width, height);
  1164. }
  1165. }
  1166.  
  1167. [html] view plain copy
  1168. package gradient;
  1169.  
  1170. import java.awt.Color;
  1171. import java.awt.Graphics2D;
  1172. import java.awt.geom.Rectangle2D;
  1173.  
  1174. /**
  1175. * 绘制Photoshop中透明色的效果.
  1176. *
  1177. * @author Biao
  1178. *
  1179. */
  1180. public class TransparentPainter {
  1181. public static void paint(Graphics2D g2d, Rectangle2D rect) {
  1182. g2d.setClip(rect);
  1183. int sx = (int) rect.getX();
  1184. int sy = (int) rect.getY();
  1185. int w = (int) rect.getWidth();
  1186. int h = (int) rect.getHeight();
  1187.  
  1188. Color color = Color.WHITE;
  1189. Color color1 = Color.WHITE;
  1190. Color color2 = Color.LIGHT_GRAY;
  1191. int delta = 10;
  1192. boolean odd = false;
  1193. for (int y = sy; y <= h + sy; y += delta) {
  1194. color = (odd) ? color1 : color2;
  1195. for (int x = sx; x <= w + sx; x += delta) {
  1196. g2d.setPaint(color);
  1197. g2d.fillRect(x, y, w, h);
  1198.  
  1199. color = (color == color1) ? color2 : color1;
  1200. }
  1201.  
  1202. odd = !odd;
  1203. }
  1204. g2d.setClip(null);
  1205. }
  1206. }
  1207.  
  1208. [html] view plain copy
  1209. package gradient;
  1210. import java.awt.geom.Point2D;
  1211.  
  1212. public class GeometryUtil {
  1213. // 两点之间的距离
  1214. public static double distanceOfPoints(Point2D p1, Point2D p2) {
  1215. double disX = p2.getX() - p1.getX();
  1216. double disY = p2.getY() - p1.getY();
  1217. double dis = Math.sqrt(disX * disX + disY * disY);
  1218.  
  1219. return dis;
  1220. }
  1221.  
  1222. // 两点的中点
  1223. public static Point2D middlePoint(Point2D p1, Point2D p2) {
  1224. double x = (p1.getX() + p2.getX()) / 2;
  1225. double y = (p1.getY() + p2.getY()) / 2;
  1226.  
  1227. return new Point2D.Double(x, y);
  1228. }
  1229.  
  1230. // 在两点所在直线上,以从startPoint到endPoint为方向,离startPoint的距离disToStartPoint的点
  1231. public static Point2D extentPoint(Point2D startPoint, Point2D endPoint, double disToStartPoint) {
  1232. double disX = endPoint.getX() - startPoint.getX();
  1233. double disY = endPoint.getY() - startPoint.getY();
  1234. double dis = Math.sqrt(disX * disX + disY * disY);
  1235. double sin = (endPoint.getY() - startPoint.getY()) / dis;
  1236. double cos = (endPoint.getX() - startPoint.getX()) / dis;
  1237. double deltaX = disToStartPoint * cos;
  1238. double deltaY = disToStartPoint * sin;
  1239.  
  1240. return new Point2D.Double(startPoint.getX() + deltaX, startPoint.getY() + deltaY);
  1241. }
  1242. }
  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. LVS原理详解及部署之二:LVS原理详解(3种工作方式8种调度算法)

    一.集群简介 什么是集群 计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一 台计算机.集群系统中的单个计 ...

  2. Python学习 - 编写自己的ORM(2)

    上一篇文章简单的实现了ORM(对象关系模型),这一篇文章主要实现简单的MySQL数据库操作. 想要操作数据库,首先要建立一个数据库连接.下面定义一个创建数据库连接的函数,得到一个连接叫做engine. ...

  3. "git add -A" is equivalent to "git add .; git add -u".

    git add -A stages All git add . stages new and modified, without deleted git add -u stages modified ...

  4. 2016021801 - Java内存区域学习笔记

    根据<深入理解java虚拟机>学习归纳整理学习笔记 程序计数器 用途:当前线程的字节码文件的行号指示器.(当前机场负责控制飞机降落的空管员:当前线程表示当前机场, 所执行的字节码等同于被等 ...

  5. servlet单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  6. BZOJ2083: [Poi2010]Intelligence test

    2083: [Poi2010]Intelligence test Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 241  Solved: 96[Sub ...

  7. 深入浅出Node.js (9) - 玩转进程

    9.1 服务模型的变迁 9.1.1 石器时代:同步 9.1.2 青铜时代:复制进程 9.1.3 白银时代:多线程 9.1.4 黄金时代:事件驱动 9.2 多进程架构 9.2.1 创建子进程 9.2.2 ...

  8. 配置Myeclipse中的项目部署到服务器,报the selected server is enabled, but is not configured properly.

    the selected server is enabled, but is not configured properly. deployment to it will not be permitt ...

  9. 如何配置jdk和tomcat 转

    一.配置JDK1.解压JDK至D:\JDK1.5目录下(楼主可以自由选取目录).2.设置环境变量(右键我得电脑->属性->高级->环境变量),在系统变量中添加一个叫JAVA_HOME ...

  10. Win32中文件的操作

    1 文件的创建或打开 HANDLE CreateFile( LPCTSTR lpFileName, //文件路径和名称 DWORD dwDesiredAccess,      //访问方式,最常用的值 ...