之前在资源接收端出现的processView,也就是进度条。在此进行展示代码以及出现的效果,其实虽说不是什么关键点,但其中牵扯到了多线程的问题。
因为对于我们接收端来说,一个发送端对应一个线程进行接收,那么对于一个文件的写操作,存在多个线程对一个文件的不同位置进行写的操作,那对于进度条的显示,当然是每一个文件对应一个进度条,并且采用一个bar对象来作为锁,因为对于多个线程写同一进度条来说,必须要顺序执行,后一个线程写的过程需要参照之前写完的位置进行续写。
观其效果
IprogressView
public interface IprogressView {
//只需要让用户使用
//1.需要根据提供的进度条个数,来生成相应个数的进度条
//2.需要完成的方法是,根据提供的显示长度,和总共需要显示的长度,进行显示,若拥有多个进度条的话,应该对应显示
void paintProgressView(List<String> fileList, String appName);//需要将需要进度条的对象与精度条进行绑定
void changeProgress(String oneBar, int perValue, int perAllLength);//通过给定的对象显示对应进度条的内容
}
progressView
对进度条接口的实现类。
public class progressView implements IprogressView, baseView {
private JFrame mainFream;
private JLabel jlbCount;
private JButton jbtClose;
private Map<String, JProgressBar> jproMap;//根据对象所对应的进度条
private volatile int count;
private String JFrameName;
private JPanel center;
public progressView() {
count = 0;
}
/*
*整体进度条的界面布局
*/
public void initalizeView() {
//size 表示的是进度条的个数,同样对应文件的个数
int size = jproMap.size();
int height = size * 100 + 75;
mainFream = new JFrame(JFrameName);
mainFream.setSize(700, height);
mainFream.setLayout(new BorderLayout());//主框采用流失布局
mainFream.setLocationRelativeTo(null);
mainFream.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFream.setResizable(false);
mainFream.add(new JLabel(" "), BorderLayout.WEST);
mainFream.add(new JLabel(" "), BorderLayout.EAST);
JPanel Jpldown = new JPanel();
Jpldown.setLayout(new BorderLayout());
mainFream.add(Jpldown, BorderLayout.SOUTH);
JLabel up = new JLabel(" ");
up.setFont(baseView.buttonFont);
Jpldown.add(up, BorderLayout.NORTH);
JLabel down = new JLabel(" ");
down.setFont(baseView.buttonFont);
Jpldown.add(down, BorderLayout.SOUTH);
JPanel centers = new JPanel();
centers.setLayout(new BorderLayout());
Jpldown.add(centers, BorderLayout.CENTER);
JPanel downwest = new JPanel();
downwest.setLayout(new BorderLayout());
centers.add(downwest, BorderLayout.WEST);
downwest.add(new JLabel(" "), BorderLayout.WEST);
JPanel downEast = new JPanel();
downEast.setLayout(new BorderLayout());
centers.add(downEast, BorderLayout.EAST);
downEast.add(new JLabel(" "), BorderLayout.EAST);
jbtClose = new JButton();
jbtClose.setText("关闭");
jbtClose.setEnabled(false);
jbtClose.setFont(baseView.buttonFont);
jbtClose.setBackground(baseView.proBackground);
downEast.add(jbtClose, BorderLayout.CENTER);
jlbCount = new JLabel();
jlbCount.setFont(baseView.buttonFont);
jlbCount.setText("成功传输" + count + "个文件");
downwest.add(jlbCount, BorderLayout.CENTER);
center = new JPanel();
center.setLayout(new GridLayout(size, 1));
mainFream.add(center, BorderLayout.CENTER);
}
/*
*根据文件的的名称生成对应文件的进度条框
*/
@Override
public void paintProgressView(List<String> object, String appname) {
//生成一个界面
this.JFrameName = appname;
jproMap = new HashMap<String, JProgressBar>();
if(object.isEmpty()) {
return;
}else {
for(String obj : object) {
JProgressBar temp = new JProgressBar();
temp.setValue(0);
temp.invalidate();
temp.setForeground(baseView.pro);
temp.setFont(baseView.buttonFont);
Border b = new LineBorder(baseView.proBorder);
temp.setBorder(BorderFactory.createLoweredBevelBorder());
temp.setStringPainted(true);
//TODO在这里设置进度条的格式
jproMap.put(obj, temp);
}
}
initalizeView();
for(String one : jproMap.keySet()) {
JPanel temp = new JPanel();
JLabel jlb = new JLabel(one);
jlb.setFont(baseView.progress);
JProgressBar jpbprogress = jproMap.get(one);
temp.setLayout(new BorderLayout());
temp.add(jlb, BorderLayout.NORTH);
temp.add(jpbprogress, BorderLayout.CENTER);//每个jpanel装一个进度条;
center.add(temp);//
}
}
public void showView() {
mainFream.setVisible(true);
dealAction();
}
/*
*添加每个进度条的侦听事件,当进度条写完时,显示传输文件的个数
*/
public void dealAction() {
for(JProgressBar one : jproMap.values()) {
one.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if(one.getValue() == 100) {
synchronized (this) {
jlbCount.setText("成功传输" + (++count) + "个文件");
}
if(count == jproMap.size()) {
jbtClose.setEnabled(true);
}
}
}
});
}
jbtClose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
closeView();
}
});
}
public void closeView() {
mainFream.dispose();
}
//对于不同的线程来说,要是访问的是同一个进度条那需要同步执行
//对于不同的线程来说,要访问不同的进度条是并形执行,互不影响,
//当然对于一个线程来说,不管是同一个还是不同个进度条,只能顺序执行
private void changeView(JProgressBar jpbprogress, int value, int allLenth) {
//不管传进来的总值是多少,根据的都是比例进行写入,最终写入进度条的值都是100
int per = (int) (value / (double) allLenth * 100.0) + 1;
jpbprogress.setValue(per);
}
@Override
public void changeProgress(String object, int value, int allLenth) {
if(object == null) {
return;
}
JProgressBar jpbMatch = this.jproMap.get(object);
//如果没有锁的情况下,每个线程需要写自己的部分,那就需要获取到当前已经写的部分,在根据自己当前写的部分加以计算
synchronized (jpbMatch) {
int count = jpbMatch.getValue();
count = (int) ((double)count / 100 * allLenth);
for (int i = 0; i <= value; i++) {
try {
changeView(jpbMatch, count + i, allLenth);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}