SwingWorker实现的简易图片浏览器

今天下班前写了一个利用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异常。

以下就是这个程序代码,有些地方都写了注释就不多说了

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;
	}
}


你可能感兴趣的:(SwingWorker实现的简易图片浏览器)