swing的进度条
JProgressBar、ProgressMonitor、BoundedRangeModel都可以用来创建进度条,我们只学习JProgressBar、BoundedRangeModel来创建进度条,另外两个类型用法进度条是图形界面中广泛使用的GUI组件,当复制一个较大的文件时,操作系统会显示一个进度条,用于标识复制操作完成的比例: 例如当启动Eclipse等程序时, 因为需要加载较多的资源, 故而启动速度较慢, 程序也会在启动过程中显示一个进度条, 用以表示该软件启动完成的比例
使用JProgressBar创建进度条的步骤,如下:
第一步:创建JProgressBar对象
xxxxxxxxxxpublic JProgressBar(int orient, int min, int max);上面那个构造方法的参数如下:
1、orint:方向,例如水平或者垂直 2、min:最小值 3、max:最大值
第二步:设置属性
setBorderPainted(boolean b):设置进度条是否有边框
setIndeterminate(boolean newValue):设置当前进度条是不是进度不确定的进度条,如果是,则将看到一个滑块在进度条中左右移动
setStringPainted(boolean b):设置进度条是否显示当前完成的百分比
第三步:获取和设置当前进度条的进度状态
setValue(int n):设置当前进度值
double getPercentComplete():获取进度条的完成百分比
String getStrin():返回进度字符串的当前值
swing的进度条_练习
xxxxxxxxxxpackage ch30;
import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;
public class a_16_0swing_进度条 {
//创建窗口 JFrame jf = new JFrame("测试进度条");
//窗口里面的左侧的复选框 JCheckBox indeterminate = new JCheckBox("不确定进度"); JCheckBox noBorder = new JCheckBox("不绘制边框");
//JProgressBar创建一个进度条,JProgressBar参数:HORIZONTAL即水平进度条、最小值、最大值 JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL,0,100);
//组装视图 public void init() {
//设置不确定进度条 indeterminate.addActionListener(new ActionListener() { //点击复选框后的事件 public void actionPerformed(ActionEvent e) { //获取一下indeterminate,即"不确定进度"复选框有没有被选中 boolean selected = indeterminate.isSelected(); //如果返回true,则当前进度条为不确定进度 bar.setIndeterminate(selected); //绘制进度条 bar.setStringPainted(!selected); } });
//设置绘制进度条的边框 noBorder.addActionListener(new ActionListener() { //点击复选框后的事件 public void actionPerformed(ActionEvent e) { //获取一下noBorder,即"不绘制边框"复选框有没有被选中 boolean flag = noBorder.isSelected(); //如果上面那行的复选框被选中,即上面那行就是true,我们就不需要绘制进度条。原因:我们的进度条默认是有边框的 bar.setBorderPainted(!flag); } });
//垂直方向的BOX容器,用来存放两个复选框 Box box = new Box(BoxLayout.Y_AXIS); box.add(indeterminate); box.add(noBorder);
//设置进度条中绘制完成百分比 bar.setStringPainted(true); //设置为默认是有边框的 bar.setBorderPainted(true);
//FlowLayout流式布局,优点:添加组件会变成从左往右添加,即就是我们要的水平布局。具体操作:把当前窗口jf的布局方式修改为FlowLayout jf.setLayout(new FlowLayout()); jf.add(box);//即96行我们组装好的容器,里面是两个垂直排列的复选框 jf.add(bar);//把我们的进度条也放进来。注意:这行的bar和上面那行的box会在jf窗口里面水平排列,或理解为左右排列
//设置进度条的最大值和最小值 bar.setMinimum(0); bar.setMaximum(100);
//设置窗口的最佳大小,设置窗口可见,设置点击叉号就退出程序 jf.pack(); jf.setVisible(true); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//模拟进度条的进度数据 for (int i = 0; i <= 100; i++) { //修改已经完成的进度,即更新最新进度 bar.setValue(i); try { //让当前线程休眠200毫秒,即每隔200毫秒进度条的百分比加1 Thread.sleep(200); } catch ( InterruptedException e) { e.printStackTrace(); } }
}
public static void main(String[] args) { new a_16_0swing_进度条().init(); }}
swing的进度条_子线程改进
xxxxxxxxxxpackage ch30;
import javax.swing.*;import javax.swing.event.ChangeEvent;import javax.swing.event.ChangeListener;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;
public class a_17_0swing_进度条_子线程改进 {
/*
上面那个休眠的线程在init方法里面写的,是在我们的主线程main里面执行的,这个休眠会直接影响到主线程,导致主程序在休眠线程还没 执行完的情况下,不会继续往下执行,整个程序就会堵塞在那个耗时操作里面
解决:耗时操作不能放到主线程里面去做,需要放到子线程里面 难点:进度条展示是在主线程,耗时操作在子线程里面,如何让子线程的完成进度实时展示在主线程上 解决:在子线程里面定义一个变量,完成度就放到这个变量里面,再在主线程里面定义一个定时器,例如每隔200毫秒就读一次子线程的变量
*/
//创建窗口 JFrame jf = new JFrame("测试进度条");
//窗口里面的左侧的复选框 JCheckBox indeterminate = new JCheckBox("不确定进度"); JCheckBox noBorder = new JCheckBox("不绘制边框");
//JProgressBar创建一个进度条,JProgressBar参数:HORIZONTAL即水平进度条、最小值、最大值 JProgressBar bar = new JProgressBar(JProgressBar.HORIZONTAL,0,100);
//组装视图 public void init() {
//设置不确定进度条 indeterminate.addActionListener(new ActionListener() { //点击复选框后的事件 public void actionPerformed(ActionEvent e) { //获取一下indeterminate,即"不确定进度"复选框有没有被选中 boolean selected = indeterminate.isSelected(); //如果返回true,则当前进度条为不确定进度 bar.setIndeterminate(selected); //绘制进度条 bar.setStringPainted(!selected); } });
//设置绘制进度条的边框 noBorder.addActionListener(new ActionListener() { //点击复选框后的事件 public void actionPerformed(ActionEvent e) { //获取一下noBorder,即"不绘制边框"复选框有没有被选中 boolean flag = noBorder.isSelected(); //如果上面那行的复选框被选中,即上面那行就是true,我们就不需要绘制进度条。原因:我们的进度条默认是有边框的 bar.setBorderPainted(!flag); } });
//垂直方向的BOX容器,用来存放两个复选框 Box box = new Box(BoxLayout.Y_AXIS); box.add(indeterminate); box.add(noBorder);
//设置进度条中绘制完成百分比 bar.setStringPainted(true); //设置为默认是有边框的 bar.setBorderPainted(true);
//FlowLayout流式布局,优点:添加组件会变成从左往右添加,即就是我们要的水平布局。具体操作:把当前窗口jf的布局方式修改为FlowLayout jf.setLayout(new FlowLayout()); jf.add(box);//即96行我们组装好的容器,里面是两个垂直排列的复选框 jf.add(bar);//把我们的进度条也放进来。注意:这行的bar和上面那行的box会在jf窗口里面水平排列,或理解为左右排列
//设置进度条的最大值和最小值 bar.setMinimum(0); bar.setMaximum(100);
//设置窗口的最佳大小,设置窗口可见,设置点击叉号就退出程序 jf.pack(); jf.setVisible(true); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//开启子线程,模拟耗时操作 SimulatedActivity simulatedActivity = new SimulatedActivity(bar.getMaximum()); //new一个线程任务,即new一个子线程并开启 new Thread(simulatedActivity).start();//这个子线程任务开启后,最下面的run方法就会开始执行,即current就会被不断修改
//设置定时任务(注意这里是父线程) Timer timer = new Timer(100, new ActionListener() { public void actionPerformed(ActionEvent e) { //读取线程任务对象的当前完成量,设置给进度条 int current = simulatedActivity.getCurrent();//父线程要通过getCurrent拿子线程的current值,就涉及下面那行的内存可见问题 //由于不是同一线程,所以我们还要考虑内存可见问题,即下面的自定义线程类的current变量前面需要加一个volatile关键字 bar.setValue(current); } }); //开启定时任务 timer.start(); //思考:上面那行的定时任务的定时器需要一直执行下去吗,显然不能,解决如下 //监听进度条的变化,如果进度完成为100%,那么停止定时器 bar.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { //当子线程的进度条为100%就停止定时器,如何知道子线程的进度条为100%呢,如下 //解决:把bar里面的进度条的最大百分比跟子线程的进度百分比做比较,如果相同,就说明达到100%,停止定时器 int value = bar.getValue(); if (value == simulatedActivity.getAmount()) { timer.stop(); } } }); }
public static void main(String[] args) { new a_17_0swing_进度条_子线程改进().init(); }
//自定义一个线程任务类,模拟耗时操作,其实这里就是子线程 private class SimulatedActivity implements Runnable {
//记录任务总量 private int amount;
//记录当前任务的完成量current。注意由于主线程和子线程不是同一线程,所以current变量前面需要加volatile关键字,意思是内存可见 private volatile int current = 0;//初始值是0 //volatile关键字可以让其他线程能拿到这个线程的current值
//由于任务总量是主线程开启时传进来的,我们需要写一个带参构造方法接收一下这个任务总量 public SimulatedActivity(int amount) { this.amount = amount; }
//get和set方法 public int getCurrent() { return current; } public void setCurrent(int current) { this.current = current; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; }
public void run() { //通过循环不断的修改current的值来实现模拟任务完成量的耗时操作。这个就是子线程的任务 while (current < amount) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } current++; } } }}