实现渐变色的JProgressBar

最近打算模仿酷狗做个音乐软件来练习,打算实现酷狗上的所有功能。但是单单在做界面时,就被卡住了,因为其中有渐变色的进度条。百度、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() {

			@Override
			public void run() {
				pbMusic.setValue(current++);
			}
		}, 0, 1000);
		contentPane.add(pbMusic);

		setLocation(400, 200);
		setSize(400, 400);
		setVisible(true);
	}
	public class GradientProgressBarUI extends BasicProgressBarUI {
		@Override
		protected 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() {

			@Override
			public 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 ++;
			
		}

		@Override
		protected void paintDeterminate(Graphics g, JComponent c) {
			Graphics2D graphics2d = (Graphics2D) g;

			Insets b = progressBar.getInsets(); // area for border
			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 - 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);
		}
	}
}




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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值