实现渐变色的JProgressBar

来源:互联网 发布:淘宝网电视图片及价格 编辑:程序博客网 时间:2024/05/29 19:38

最近打算模仿酷狗做个音乐软件来练习,打算实现酷狗上的所有功能。但是单单在做界面时,就被卡住了,因为其中有渐变色的进度条。百度、google了好长时间,也没有找到解决方案,只看到说要重写BasicProgressBarUI,于是就了解了这个类,并阅读这个类的源代码,打算自己重写这个类的关于JProgressBar的外表的方法。发现有两个,一个是paintIndeterminate方法,另一个是paintDeterminate方法。下面我将详细说明重写过程中我遇到的弯路。

第一个是,看API文档中,发现paintIndeterminate这个方法是要自己重新做一个进度条时要重写的。但是重写时,我用的LinearGradientPaint类的对象,它的效果一直显示不出来。而paintDeterminate这个方法是要实现圆角进度条时要重写的,我重写了这个方法,它的效果反而就能显示出来。在这我就纳闷了,我又不想实现圆角的外观,只是想要实现渐变色的进度条,为何重写这个方法才管用?有高人知道还请留言指点。幸好最后我通过fillRoundRect这个方法,实现了自己想要的效果。

第二个是,关于LinearGradientPaint这个类。这个类有的初始化函数,有这样的一个:

LinearGradientPaint(Point2D p1,Point2D p2,float[] dist,Color[] colors,CycleMethod cycleMethod)
每个参数的具体含义还请自行参阅API文档,我只提两件事:

   ①colors这个数组中,至少得有两个颜色。

   ②dist这个数组中,值的个数要和colors数组的值的个数相等。而且里面的值还得是递增的。

   刚开始我就用的这个类的实例,但是做出来的效果一直特别奇怪。这是挺痛苦的一段代码,各位自己来实现这个类试试就行。也许是我功力太低,这个类用不明白。

   后来在论坛上有高人回复我的帖子说用GradientPaint这个类,于是我就试了下,现在是实现了这个酷狗上进度条的效果。只是那个一闪一闪的两亮点还是没有实现。下面我先贴出来效果图:


  下面贴出来代码,写的有点不规范,大家凑合看:

package test;import java.awt.Color;import java.awt.GradientPaint;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Insets;import java.awt.geom.Point2D;import java.util.ArrayList;import java.util.Timer;import java.util.TimerTask;import javax.swing.JComponent;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JProgressBar;import javax.swing.plaf.basic.BasicProgressBarUI;public class test extends JFrame {int current = 0;public static void main(String[] args) {new test().setVisible(true);}public test() {JPanel contentPane = new JPanel();setContentPane(contentPane);contentPane.setBounds(0, 0, 400, 400);final JProgressBar pbMusic = new JProgressBar();pbMusic.setBounds(16, 38, 332, 4);pbMusic.setValue(current);pbMusic.setMaximum(100);pbMusic.setUI(new GradientProgressBarUI());pbMusic.setBorderPainted(false);new Timer().schedule(new TimerTask() {@Overridepublic void run() {pbMusic.setValue(current++);}}, 0, 1000);contentPane.add(pbMusic);setLocation(400, 200);setSize(400, 400);setVisible(true);}public class GradientProgressBarUI extends BasicProgressBarUI {@Overrideprotected void paintDeterminate(Graphics g, JComponent c) {Graphics2D graphics2d = (Graphics2D) g;Insets b = progressBar.getInsets(); // JProgressBar的边界区域int width = progressBar.getWidth();int height = progressBar.getHeight();int barRectWidth = width - (b.right + b.left);int barRectHeight = height - (b.top + b.bottom);int arcSize = height / 2 - 1;int amountFull = getAmountFull(b, barRectWidth, barRectHeight);//已完成的进度graphics2d.setColor(Color.WHITE);graphics2d.fillRoundRect(0, 0, width - 1, height, arcSize,arcSize);//绘制JProgressBar的背景//用GradientPaint类来实现渐变色显示进度//设置了开始点和终止点,并设置好这两个点的颜色,系统会自动在这两个点中用渐变色来填充Point2D start = new Point2D.Float(0, 0);Point2D end = new Point2D.Float(amountFull - 1, barRectHeight - 1);//这里设置的终止点是当前已经完成的进度的那个点GradientPaint gradientPaint = new GradientPaint(start, new Color(114,243,233), end, new Color(233,243,123));graphics2d.setPaint(gradientPaint);graphics2d.fillRoundRect(b.left, b.top, amountFull - 1,barRectHeight, arcSize, arcSize);//这里实现的是圆角的效果将arcSize调成0即可实现矩形效果}}}


各位可以用LinearGradientPaint自己实现看看。


其实在那位高人提出来用GradientPaint方法前,我还想过另一种方法。下面我说一下思路:各位看上面的代码能够看到,最终是用Graphics2D的fillRoundRect来实现绘制的,而且,这个方法的四个参数,前两个是左上角的坐标,随后的两个参数是填充区域的宽度和高度,最后的两个是圆角的水平直径和垂直直径。那么,我们能不能每次绘制完当前区域,然后用几个变量记住下次绘制的起点,当前绘制区域的终点就是下次绘制的起点,因为我通过源代码发现,每次进度值改变时,都是要重新绘制进度条的。我的想法就是,我们指定好下次绘制时绘制区域的坐标,以及颜色,这样连续的多个绘制区域拼接起来,也能形成一个渐变色的进度条的效果。下面我贴出来我的这个方法的代码,效果怎样请各位自行运行,其中有些地方和上面的代码中是一样的,我就没加注释:


package test;import java.awt.Color;import java.awt.GradientPaint;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Insets;import java.awt.geom.Point2D;import java.util.ArrayList;import java.util.Timer;import java.util.TimerTask;import javax.swing.JComponent;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JProgressBar;import javax.swing.plaf.basic.BasicProgressBarUI;public class test extends JFrame {int current = 0;public static void main(String[] args) {new test().setVisible(true);}public test() {JPanel contentPane = new JPanel();setContentPane(contentPane);contentPane.setBounds(0, 0, 400, 400);final JProgressBar pbMusic = new JProgressBar();pbMusic.setBounds(16, 38, 332, 4);pbMusic.setValue(current);pbMusic.setMaximum(100);pbMusic.setUI(new GradientProgressBarUI());pbMusic.setBorderPainted(false);new Timer().schedule(new TimerTask() {@Overridepublic void run() {pbMusic.setValue(current++);}}, 0, 1000);contentPane.add(pbMusic);setLocation(400, 200);setSize(400, 400);setVisible(true);}public class GradientProgressBarUI extends BasicProgressBarUI {private int increment = 0;// 控制颜色的增量int x =0;int y = 0;// 设置颜色的增量private void setIncrement() {increment ++;}@Overrideprotected void paintDeterminate(Graphics g, JComponent c) {Graphics2D graphics2d = (Graphics2D) g;Insets b = progressBar.getInsets(); // area for borderint width = progressBar.getWidth();int height = progressBar.getHeight();int barRectWidth = width - (b.right + b.left);int barRectHeight = height - (b.top + b.bottom);int arcSize = height / 2 - 1;int amountFull = getAmountFull(b, barRectWidth, barRectHeight);graphics2d.setColor(Color.WHITE);graphics2d.fillRoundRect(0, 0, width - 1, height - 1, arcSize,arcSize);graphics2d.setColor(getColor());if (x == 0) {//第一次绘制时的区域graphics2d.fillRect(b.left, b.top, amountFull - 1,barRectHeight - 1);}else {//除了第一次绘制以外的绘制区域//因为每次绘制时高度都是一样的,所以y坐标以及高度都没变。只是起始的x坐标以及宽度变了//其实想想宽度也没变,因为是通过Timer来控制的,每过一秒重新绘制一次。而每一秒走过的宽度应该是相同的graphics2d.fillRect(x, b.top, amountFull - x - 1,barRectHeight - 1);}x = amountFull;//设置下次绘制的起点,让当前绘制区域的终点等于下次绘制的起点}//获取这次绘制的区域的颜色private Color getColor(){setIncrement();return new Color(112 + increment,246,238 - increment);}}}




只是这种方法在绘制时,前一次绘制的都会没有了。只有这次绘制的区域。运行过的应该能看到。所以现在的问题是如何在绘制新的区域时,保留着以前绘制的区域呢?请高人指点。虽然这种方法即使实现也挺麻烦,但是我想试试。

1 0
原创粉丝点击