今天下班前写了一个利用SwingWorker来实现载入一个指定文件夹下所有图片的演示程序,网上和很多书都已有对SwingWorker的使用介绍的很多,因此我也不必多说什么,只是结合这个演示程序来说说我对这个类使用心得。一般使用SwingWorker时都是直接继承一个子类来使用,例如在我的程序里我继承的子类名为ImageWorker,因此在调用时就为:
ImageWorker worker = new ImageWorker(imagePath, (DefaultListModel) list.getModel(), this);
其中的imagePath和list.getModel是给传递给这个类使用的。而要让这个类真正的运行起来的语句则是:
worker.execute();
SwingWorker一旦运行起来则会创建一个新的线程,并立即调用doInBackground方法,于是我们可以在这个方法中编写相关的代码,如读取大容量的文件或多个的文件都一些费时的操作,并且可以根据需要用publish发布一些表示当前进度的信息,而一旦publish被调用后会立即调用process方法,该方法用于接收publish传入参数集并用于程序界面的更新,当doInBackground运行结束后会调用done方法,我在这个方法里使用get方法得到doInBackground方法的返回值。
还要提一下的是不要在启动了SwingWorker的代码处(既work.execute处)直接使用get方法来得到doInBackground的返回值,例如:
worker.execute();
Map images = worker.get();
这样只会使界面卡死,直到SwingWorker全部运行完毕,因此execute是启动了一个线程后,在doInBackground尚未运行完毕时程序就运行到了Map images = worker.get()这句。
SwingWorker可以通过cancel方法取消载入进程,但进程并不立即停止,还需要在process方法用isCancelled方法进行判断,而且cancel方法被调用再使用get方法时会抛出InterruptedException异常和CancellationException异常。
ImageWorker worker = new ImageWorker(imagePath, (DefaultListModel) list.getModel(), this);
其中的imagePath和list.getModel是给传递给这个类使用的。而要让这个类真正的运行起来的语句则是:
worker.execute();
SwingWorker一旦运行起来则会创建一个新的线程,并立即调用doInBackground方法,于是我们可以在这个方法中编写相关的代码,如读取大容量的文件或多个的文件都一些费时的操作,并且可以根据需要用publish发布一些表示当前进度的信息,而一旦publish被调用后会立即调用process方法,该方法用于接收publish传入参数集并用于程序界面的更新,当doInBackground运行结束后会调用done方法,我在这个方法里使用get方法得到doInBackground方法的返回值。
还要提一下的是不要在启动了SwingWorker的代码处(既work.execute处)直接使用get方法来得到doInBackground的返回值,例如:
worker.execute();
Map images = worker.get();
这样只会使界面卡死,直到SwingWorker全部运行完毕,因此execute是启动了一个线程后,在doInBackground尚未运行完毕时程序就运行到了Map images = worker.get()这句。
SwingWorker可以通过cancel方法取消载入进程,但进程并不立即停止,还需要在process方法用isCancelled方法进行判断,而且cancel方法被调用再使用get方法时会抛出InterruptedException异常和CancellationException异常。
以下就是这个程序代码,有些地方都写了注释就不多说了
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ImageViewer extends JFrame
{
private static String imagePath;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// 弹出了一个对话框用于为程序指定一个文件夹
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = chooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION)
{
// 得到图片路径
imagePath = chooser.getSelectedFile().getPath();
ImageViewer viewer = new ImageViewer();
viewer.loadImage();
}
}
});
}
private JSplitPane spaContent;
private JList list;
private JPanel paImage;
private Image img;
private Map<String, Image> images;
public ImageViewer()
{
super("简易图片浏览器");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initUI();
}
private void initUI()
{
// 初始化主程序界面
initPanel();
this.setContentPane(spaContent);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private void initPanel()
{
// 设置一个分隔面板,面板默认为左右分隔并在分隔条上显示折叠按钮
spaContent = new JSplitPane();
spaContent.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
spaContent.setOneTouchExpandable(true);
spaContent.setPreferredSize(new Dimension(500, 300));
spaContent.setDividerLocation(200);
spaContent.setLeftComponent(initList()); // 左侧用以显示文件列表
spaContent.setRightComponent(initView()); // 右侧用于显示图像
}
private JScrollPane initList()
{
// 设置一个列表控件以接收图像文件的文件名
list = new JList(new DefaultListModel());
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // 设置为单选
list.getSelectionModel().addListSelectionListener(new ListSelectionListener()
{
// 当单击列表项后根据文件名来显示图像
public void valueChanged(ListSelectionEvent arg0)
{
if (images != null)
{
String key = list.getSelectedValue().toString(); // 得到键值
img = images.get(key); // 得到图像
paImage.repaint(); // 刷新右侧的图像显示面板
}
}
});
return new JScrollPane(list);
}
private JPanel initView()
{
paImage = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
if (img != null)
{
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
}
};
return paImage;
}
public void loadImage()
{
ImageWorker worker = new ImageWorker(imagePath, (DefaultListModel) list.getModel(), this);
worker.execute();
}
public Map<String, Image> getImages()
{
return this.images;
}
public void setImages(Map<String, Image> images)
{
this.images = images;
}
}
class ImageWorker extends SwingWorker<Map<String, Image>, String>
{
private String imagePath;
private DefaultListModel dlm;
private ImageViewer view;
private JDialog dlg;
private JLabel lblText;
private JButton btnStop;
public ImageWorker(String imagePath, DefaultListModel dlm, ImageViewer view)
{
this.dlm = dlm;
this.imagePath = imagePath;
this.view = view;
initDialog();
}
private void initDialog()
{
// 初始化一个对话框用于显示正在载入的文件名称
dlg = new JDialog();
dlg.setUndecorated(true);
dlg.setAlwaysOnTop(true);
JPanel pa = new JPanel();
dlg.setContentPane(pa);
// 创建一个文本控件
lblText = new JLabel();
lblText.setPreferredSize(new Dimension(350, 25));
lblText.setHorizontalAlignment(SwingConstants.CENTER);
pa.add(lblText);
// 创建一个按钮用于
pa.add(btnStop = new JButton("取消"));
btnStop.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
ImageWorker.this.cancel(true);
}
});
dlg.pack();
dlg.setLocationRelativeTo(view);
dlg.setVisible(true);
}
protected void process(List<String> arg0)
{
// 程序在接到发布信息后便调用此方法
if (this.isCancelled())
return;
for (String f : arg0)
{
dlm.addElement(f);
lblText.setText(f + " 载入成功!");
}
}
protected void done()
{
// 当doInBackground方法结束后会调用此方法
super.done();
dlg.dispose();
try
{
// 通过get方法得到doInBackground的返回值并赋给ImageViewer实例的映像集合
view.setImages(this.get());
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CancellationException e)
{
System.out.println("程序被取消载入");
} catch (ExecutionException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected Map<String, Image> doInBackground() throws Exception
{
System.out.println(Thread.currentThread().getName());
// 创建一个映像集合
Map<String, Image> images = new HashMap<String, Image>();
// 得到图像路径下的所有文件
File path = new File(imagePath);
String[] files = path.list();
if (files.length != 0)
{
for (int i = 0; i < files.length; i++)
{
// 对所得到文件名进行分析,只对图像文件进行操作
String ext = files[i].substring(files[i].length() - 4, files[i].length());
if (ext.equals(".jpg") || ext.equals(".png") || ext.equals(".gif"))
{
try
{
// 读取图像文件
Image img = ImageIO.read(new File(imagePath + "\\" + files[i]));
images.put(files[i], img); // 以文件名为键,以图像为值载入到映像集合里
this.publish(files[i]); // 向工作器发布已载入的文件名,此方法将调用process方法
Thread.sleep(500); // 使用一个延时以便于看清载入的进度
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
return images;
}
}