swing的进度条
JProgressBar、ProgressMonitor、BoundedRangeModel都可以用来创建进度条,我们只学习JProgressBar、BoundedRangeModel来创建进度条,另外两个类型用法进度条是图形界面中广泛使用的GUI组件,当复制一个较大的文件时,操作系统会显示一个进度条,用于标识复制操作完成的比例: 例如当启动Eclipse等程序时, 因为需要加载较多的资源, 故而启动速度较慢, 程序也会在启动过程中显示一个进度条, 用以表示该软件启动完成的比例
使用JProgressBar创建进度条的步骤,如下:
第一步:创建JProgressBar对象
xxxxxxxxxx
public 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的进度条_练习
xxxxxxxxxx
package 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的进度条_子线程改进
xxxxxxxxxx
package 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++;
}
}
}
}