我们在多文件下载或多事务处理时,经常会出现使用线程以提高效率的情况,而这时在GUI程序中如何表示进度,就成了一个不大不小的问题。 现在比较被大众接受的方式,大体就是如迅雷等下载工具中一样,用表格中加载进度条以进行显示。 而对于Swing来说,并没有现成的组件能够实现这一操作,还有下载的并发,似乎也需要额外进行处理。于是,我在此提供一个基于jdk1.6版本的示例,以供参考。(因为jdk1.6提供了SwingWorker,简化了图形程序中的线程处理,使用其他jdk开发请替换此项即可)本示例由两个java文件组成MyTableModel.javapackage org.loon.test;import java.awt.Component;import java.util.HashMap;import java.util.Map;import javax.swing.BorderFactory;import javax.swing.JProgressBar;import javax.swing.JTable;import javax.swing.SwingWorker;import javax.swing.table.DefaultTableCellRenderer;import javax.swing.table.DefaultTableModel;/** *//** * <p> * Title: LoonFramework * </p> * <p> * Description: * </p> * <p> * Copyright: Copyright (c) 2007 * </p> * <p> * Company: LoonFramework * </p> * * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */public class MyTableModel extends DefaultTableModel ...{ /** *//** * */ private static final long serialVersionUID = 1L; private static final ColumnContext[] columnArray = ...{ new ColumnContext("ID", Integer.class, false), new ColumnContext("名称", String.class, false), new ColumnContext("进度", Integer.class, false) }; private final Map<Integer, SwingWorker> swmap = new HashMap<Integer, SwingWorker>(); private int number = 0; public void addTest(Test t, SwingWorker worker) ...{ Object[] obj = ...{ new Integer(number), t.getName(), t.getProgress() }; super.addRow(obj); swmap.put(number, worker); number++; } public synchronized SwingWorker getSwingWorker(int identifier) ...{ Integer key = (Integer) getValueAt(identifier, 0); return swmap.get(key); } public Test getTest(int identifier) ...{ return new Test((String) getValueAt(identifier, 1), (Integer) getValueAt(identifier, 2)); } public boolean isCellEditable(int row, int col) ...{ return columnArray[col].isEditable; } public Class<?> getColumnClass(int modelIndex) ...{ return columnArray[modelIndex].columnClass; } public int getColumnCount() ...{ return columnArray.length; } public String getColumnName(int modelIndex) ...{ return columnArray[modelIndex].columnName; } private static class ColumnContext ...{ public final String columnName; public final Class columnClass; public final boolean isEditable; public ColumnContext(String columnName, Class columnClass, boolean isEditable) ...{ this.columnName = columnName; this.columnClass = columnClass; this.isEditable = isEditable; } }}class Test ...{ private String name; private Integer progress; public Test(String name, Integer progress) ...{ this.name = name; this.progress = progress; } public void setName(String str) ...{ name = str; } public void setProgress(Integer str) ...{ progress = str; } public String getName() ...{ return name; } public Integer getProgress() ...{ return progress; }}class ProgressRenderer extends DefaultTableCellRenderer ...{ /** *//** * */ private static final long serialVersionUID = 1L; private final JProgressBar b = new JProgressBar(0, 100); public ProgressRenderer() ...{ super(); setOpaque(true); b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) ...{ Integer i = (Integer) value; String text = "完成"; if (i < 0) ...{ //删除 text = "取消完毕"; } else if (i < 100) ...{ b.setValue(i); return b; } super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column); return this; }}MyPanel.javapackage org.loon.test;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Component;import java.awt.Dimension;import java.awt.EventQueue;import java.awt.event.ActionEvent;import java.util.HashSet;import java.util.Random;import javax.swing.AbstractAction;import javax.swing.Action;import javax.swing.Icon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JPopupMenu;import javax.swing.JScrollPane;import javax.swing.JSeparator;import javax.swing.JTable;import javax.swing.RowFilter;import javax.swing.SwingWorker;import javax.swing.WindowConstants;import javax.swing.table.TableCellRenderer;import javax.swing.table.TableColumn;import javax.swing.table.TableRowSorter;//import org.loon.framework.dll.NativeLoader;/** *//** * <p> * Title: LoonFramework * </p> * <p> * Description: * </p> * <p> * Copyright: Copyright (c) 2007 * </p> * <p> * Company: LoonFramework * </p> * * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */public class MyPanel extends JPanel ...{ /** *//** * */ private static final long serialVersionUID = 1L; private static final Color evenColor = new Color(250, 250, 250); private final MyTableModel model = new MyTableModel(); private final TableRowSorter<MyTableModel> sorter = new TableRowSorter<MyTableModel>( model); private final JTable table; public MyPanel() ...{ super(new BorderLayout()); table = new JTable(model) ...{ /** *//** * */ private static final long serialVersionUID = 1L; public Component prepareRenderer( TableCellRenderer tableCellRenderer, int row, int column) ...{ Component component = super.prepareRenderer(tableCellRenderer, row, column); //背景色及字体设置 if (isRowSelected(row)) ...{ component.setForeground(getSelectionForeground()); component.setBackground(getSelectionBackground()); } else ...{ component.setForeground(getForeground()); component.setBackground((row % 2 == 0) ? evenColor : table .getBackground()); } return component; } public JPopupMenu getComponentPopupMenu() ...{ return makePopup(); } }; table.setRowSorter(sorter); model.addTest(new Test("进度条测试", 100), null); // 滚动条 JScrollPane scrollPane = new JScrollPane(table); // 背景色 scrollPane.getViewport().setBackground(Color.black); // 弹出菜单 table.setComponentPopupMenu(new JPopupMenu()); // 是否始终大到足以填充封闭视口的高度 table.setFillsViewportHeight(true); // 将单元格间距的高度和宽度设置为指定的Dimension table.setIntercellSpacing(new Dimension()); // 是否绘制单元格间的水平线 table.setShowHorizontalLines(true); // 是否绘制单元格间的垂直线 table.setShowVerticalLines(false); // 停止编辑时重新定义焦点,避免TableCellEditor丢失数据 table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); // 表示JTable中列的所有属性,如宽度、大小可调整性、最小和最大宽度等。 TableColumn column = table.getColumnModel().getColumn(0); column.setMaxWidth(60); column.setMinWidth(60); column.setResizable(false); column = table.getColumnModel().getColumn(2); // 绘制此列各值的TableCellRenderer column.setCellRenderer(new ProgressRenderer()); // 添加按钮 add(new JButton(new CreateNewAction("添加", null)), BorderLayout.SOUTH); add(scrollPane, BorderLayout.CENTER); setPreferredSize(new Dimension(320, 180)); } class CreateNewAction extends AbstractAction ...{ /** *//** * */ private static final long serialVersionUID = 1L; public CreateNewAction(String label, Icon icon) ...{ super(label, icon); } public void actionPerformed(ActionEvent evt) ...{ createNewActionPerformed(evt); } } /** *//** * 创建事件 * @param evt */ private void createNewActionPerformed(ActionEvent evt) ...{ final int key = model.getRowCount(); //在jdk1.6后,当一个Swing程序需要执行一个多线程任务时,可以通过javax.swing.SwingWorker实例进行实现。 //SwingWorker的process可以定义约束属性。更改这些属性将触发事件,并从事件调度线程上引起事件处理方法的调用。 //SwingWorker的done方法,在后台任务完成时自动的在事件调度线程上被调用。 SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() ...{ // 随机sleep private int sleepDummy = new Random().nextInt(100) + 1; // 最大任务数量 private int taskSize = 200; protected Integer doInBackground() ...{ int current = 0; while (current < taskSize && !isCancelled()) ...{ current++; try ...{ Thread.sleep(sleepDummy); } catch (InterruptedException ie) ...{ publish(-1); break; } publish(100 * current / taskSize); } return sleepDummy * taskSize; } /** *//** * 进行中处理 */ protected void process(java.util.List<Integer> data) ...{ for (Integer value : data) ...{ // 把数据填入对应的行列 model.setValueAt(value, key, 2); } // 传送变更事件给指定行列 model.fireTableCellUpdated(key, 2); } /** *//** * 完成后处理 */ protected void done() ...{ } }; model.addTest(new Test("进度条测试", 0), worker); worker.execute(); } class CancelAction extends AbstractAction ...{ /** *//** * */ private static final long serialVersionUID = 1L; public CancelAction(String label, Icon icon) ...{ super(label, icon); } public void actionPerformed(ActionEvent evt) ...{ cancelActionPerformed(evt); } } /** *//** * 取消进度 * @param evt */ public synchronized void cancelActionPerformed(ActionEvent evt) ...{ int[] selection = table.getSelectedRows(); if (selection == null || selection.length <= 0) return; for (int i = 0; i < selection.length; i++) ...{ int midx = table.convertRowIndexToModel(selection[i]); SwingWorker worker = model.getSwingWorker(midx); if (worker != null && !worker.isDone()) ...{ worker.cancel(true); } worker = null; } table.repaint(); } /** *//** * 取消下载进程 * * @author chenpeng * */ class DeleteAction extends AbstractAction ...{ /** *//** * */ private static final long serialVersionUID = 1L; public DeleteAction(String label, Icon icon) ...{ super(label, icon); } public void actionPerformed(ActionEvent evt) ...{ deleteActionPerformed(evt); } } private final HashSet<Integer> set = new HashSet<Integer>(); public synchronized void deleteActionPerformed(ActionEvent evt) ...{ int[] selection = table.getSelectedRows(); if (selection == null || selection.length <= 0) return; for (int i = 0; i < selection.length; i++) ...{ int midx = table.convertRowIndexToModel(selection[i]); set.add(midx); SwingWorker worker = model.getSwingWorker(midx); if (worker != null && !worker.isDone()) ...{ worker.cancel(true); } worker = null; } // JTable过滤器 final RowFilter<MyTableModel, Integer> filter = new RowFilter<MyTableModel, Integer>() ...{ public boolean include( Entry<? extends MyTableModel, ? extends Integer> entry) ...{ Integer midx = entry.getIdentifier(); return !set.contains(midx); } }; sorter.setRowFilter(filter); table.repaint(); } private JPopupMenu makePopup() ...{ JPopupMenu pop = new JPopupMenu(); Action act = new CreateNewAction("添加", null); pop.add(act); act = new CancelAction("取消", null); int[] selection = table.getSelectedRows(); if (selection == null || selection.length <= 0) act.setEnabled(false); pop.add(act); // 分割线 pop.add(new JSeparator()); act = new DeleteAction("删除", null); if (selection == null || selection.length <= 0) act.setEnabled(false); pop.add(act); return pop; } public static void main(String[] args) ...{ EventQueue.invokeLater(new Runnable() ...{ public void run() ...{ createGUI(); } }); } public static void createGUI() ...{ JFrame frame = new JFrame("在JTable中加载进度条及进行操作"); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.getContentPane().add(new MyPanel()); frame.setSize(400, 400); // 透明度90% // NativeLoader.getInstance().setTransparence(frame, 0.9f); // 居中 frame.setLocationRelativeTo(null); frame.setVisible(true); }}运行效果如下:
本文转自 cping 51CTO博客,原文链接:http://blog.51cto.com/cping1982/130108