我们在多文件下载或多事务处理时,经常会出现使用线程以提高效率的情况,而这时在GUI程序中如何表示进度,就成了一个不大不小的问题。
现在比较被大众接受的方式,大体就是如迅雷等下载工具中一样,用表格中加载进度条以进行显示。
而对于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(Testt,SwingWorkerworker)
{
Object[]obj
=
{
new
Integer(number),t.getName(),t.getProgress()}
;
super
.addRow(obj);
swmap.put(number,worker);
number
++
;
}
public
synchronized
SwingWorkergetSwingWorker(
int
identifier)
{
Integerkey
=
(Integer)getValueAt(identifier,
0
);
return
swmap.get(key);
}
public
TestgetTest(
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
StringgetColumnName(
int
modelIndex)
{
return
columnArray[modelIndex].columnName;
}
private
static
class
ColumnContext
{
public
final
StringcolumnName;
public
final
ClasscolumnClass;
public
final
boolean
isEditable;
public
ColumnContext(StringcolumnName,ClasscolumnClass,
boolean
isEditable)
{
this
.columnName
=
columnName;
this
.columnClass
=
columnClass;
this
.isEditable
=
isEditable;
}
}
}
class
Test
{
private
Stringname;
private
Integerprogress;
public
Test(Stringname,Integerprogress)
{
this
.name
=
name;
this
.progress
=
progress;
}
public
void
setName(Stringstr)
{
name
=
str;
}
public
void
setProgress(Integerstr)
{
progress
=
str;
}
public
StringgetName()
{
return
name;
}
public
IntegergetProgress()
{
return
progress;
}
}
class
ProgressRenderer
extends
DefaultTableCellRenderer
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
private
final
JProgressBarb
=
new
JProgressBar(
0
,
100
);
public
ProgressRenderer()
{
super
();
setOpaque(
true
);
b.setBorder(BorderFactory.createEmptyBorder(
1
,
1
,
1
,
1
));
}
public
ComponentgetTableCellRendererComponent(JTabletable,Objectvalue,
boolean
isSelected,
boolean
hasFocus,
int
row,
int
column)
{
Integeri
=
(Integer)value;
Stringtext
=
"
完成
"
;
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;
//
importorg.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
ColorevenColor
=
new
Color(
250
,
250
,
250
);
private
final
MyTableModelmodel
=
new
MyTableModel();
private
final
TableRowSorter
<
MyTableModel
>
sorter
=
new
TableRowSorter
<
MyTableModel
>
(
model);
private
final
JTabletable;
public
MyPanel()
{
super
(
new
BorderLayout());
table
=
new
JTable(model)
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
public
ComponentprepareRenderer(
TableCellRenderertableCellRenderer,
int
row,
int
column)
{
Componentcomponent
=
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
JPopupMenugetComponentPopupMenu()
{
return
makePopup();
}
}
;
table.setRowSorter(sorter);
model.addTest(
new
Test(
"
进度条测试
"
,
100
),
null
);
//
滚动条
JScrollPanescrollPane
=
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中列的所有属性,如宽度、大小可调整性、最小和最大宽度等。
TableColumncolumn
=
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(Stringlabel,Iconicon)
{
super
(label,icon);
}
public
void
actionPerformed(ActionEventevt)
{
createNewActionPerformed(evt);
}
}
/**
*创建事件
*
@param
evt
*/
private
void
createNewActionPerformed(ActionEventevt)
{
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
IntegerdoInBackground()
{
int
current
=
0
;
while
(current
<
taskSize
&&
!
isCancelled())
{
current
++
;
try
{
Thread.sleep(sleepDummy);
}
catch
(InterruptedExceptionie)
{
publish(
-
1
);
break
;
}
publish(
100
*
current
/
taskSize);
}
return
sleepDummy
*
taskSize;
}
/**
*进行中处理
*/
protected
void
process(java.util.List
<
Integer
>
data)
{
for
(Integervalue: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(Stringlabel,Iconicon)
{
super
(label,icon);
}
public
void
actionPerformed(ActionEventevt)
{
cancelActionPerformed(evt);
}
}
/**
*取消进度
*
@param
evt
*/
public
synchronized
void
cancelActionPerformed(ActionEventevt)
{
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]);
SwingWorkerworker
=
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(Stringlabel,Iconicon)
{
super
(label,icon);
}
public
void
actionPerformed(ActionEventevt)
{
deleteActionPerformed(evt);
}
}
private
final
HashSet
<
Integer
>
set
=
new
HashSet
<
Integer
>
();
public
synchronized
void
deleteActionPerformed(ActionEventevt)
{
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);
SwingWorkerworker
=
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)
{
Integermidx
=
entry.getIdentifier();
return
!
set.contains(midx);
}
}
;
sorter.setRowFilter(filter);
table.repaint();
}
private
JPopupMenumakePopup()
{
JPopupMenupop
=
new
JPopupMenu();
Actionact
=
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()
{
JFrameframe
=
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
);
}
}
运行效果如下:
现在比较被大众接受的方式,大体就是如迅雷等下载工具中一样,用表格中加载进度条以进行显示。
而对于Swing来说,并没有现成的组件能够实现这一操作,还有下载的并发,似乎也需要额外进行处理。于是,我在此提供一个基于jdk1.6版本的示例,以供参考。(因为jdk1.6提供了SwingWorker,简化了图形程序中的线程处理,使用其他jdk开发请替换此项即可)
本示例由两个java文件组成
MyTableModel.java

























































































































































MyPanel.java





























































































































































































































































































































运行效果如下:
