我们在多文件下载或多事务处理时,经常会出现使用线程以提高效率的情况,而这时在GUI程序中如何表示进度,就成了一个不大不小的问题。
现在比较被大众接受的方式,大体就是如迅雷等下载工具中一样,用表格中加载进度条以进行显示。
而对于Swing来说,并没有现成的组件能够实现这一操作,还有下载的并发,似乎也需要额外进行处理。于是,我在此提供一个基于jdk1.6版本的示例,以供参考。(因为jdk1.6提供了SwingWorker,简化了图形程序中的线程处理,使用其他jdk开发请替换此项即可)
本示例由两个java文件组成
MyTableModel.java
MyPanel.java
现在比较被大众接受的方式,大体就是如迅雷等下载工具中一样,用表格中加载进度条以进行显示。
而对于Swing来说,并没有现成的组件能够实现这一操作,还有下载的并发,似乎也需要额外进行处理。于是,我在此提供一个基于jdk1.6版本的示例,以供参考。(因为jdk1.6提供了SwingWorker,简化了图形程序中的线程处理,使用其他jdk开发请替换此项即可)
本示例由两个java文件组成
MyTableModel.java
package
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:ceponline@yahoo.com.cn
* @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;
}
}
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:ceponline@yahoo.com.cn
* @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.java
package
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:ceponline@yahoo.com.cn
* @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);
}
}
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:ceponline@yahoo.com.cn
* @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);
}
}