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

importjava.awt.Component;
importjava.util.HashMap;
importjava.util.Map;

importjavax.swing.BorderFactory;
importjavax.swing.JProgressBar;
importjavax.swing.JTable;
importjavax.swing.SwingWorker;
importjavax.swing.table.DefaultTableCellRenderer;
importjavax.swing.table.DefaultTableModel;


/***//**
*<p>
*Title:LoonFramework
*</p>
*<p>
*Description:
*</p>
*<p>
*Copyright:Copyright(c)2007
*</p>
*<p>
*Company:LoonFramework
*</p>
*
*@authorchenpeng
*@email:[email protected]
*@version0.1
*/

publicclassMyTableModelextendsDefaultTableModel...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;


privatestaticfinalColumnContext[]columnArray=...{
newColumnContext("ID",Integer.class,false),
newColumnContext("名称",String.class,false),
newColumnContext("进度",Integer.class,false)};

privatefinalMap<Integer,SwingWorker>swmap=newHashMap<Integer,SwingWorker>();

privateintnumber=0;


publicvoidaddTest(Testt,SwingWorkerworker)...{

Object[]obj=...{newInteger(number),t.getName(),t.getProgress()};
super.addRow(obj);
swmap.put(number,worker);
number++;
}


publicsynchronizedSwingWorkergetSwingWorker(intidentifier)...{
Integerkey=(Integer)getValueAt(identifier,0);
returnswmap.get(key);
}


publicTestgetTest(intidentifier)...{
returnnewTest((String)getValueAt(identifier,1),
(Integer)getValueAt(identifier,2));
}


publicbooleanisCellEditable(introw,intcol)...{
returncolumnArray[col].isEditable;
}



publicClass<?>getColumnClass(intmodelIndex)...{
returncolumnArray[modelIndex].columnClass;
}


publicintgetColumnCount()...{
returncolumnArray.length;
}


publicStringgetColumnName(intmodelIndex)...{
returncolumnArray[modelIndex].columnName;
}


privatestaticclassColumnContext...{
publicfinalStringcolumnName;

publicfinalClasscolumnClass;

publicfinalbooleanisEditable;

publicColumnContext(StringcolumnName,ClasscolumnClass,

booleanisEditable)...{
this.columnName=columnName;
this.columnClass=columnClass;
this.isEditable=isEditable;
}
}
}


classTest...{
privateStringname;

privateIntegerprogress;


publicTest(Stringname,Integerprogress)...{
this.name=name;
this.progress=progress;
}


publicvoidsetName(Stringstr)...{
name=str;
}


publicvoidsetProgress(Integerstr)...{
progress=str;
}


publicStringgetName()...{
returnname;
}


publicIntegergetProgress()...{
returnprogress;
}
}


classProgressRendererextendsDefaultTableCellRenderer...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;
privatefinalJProgressBarb=newJProgressBar(0,100);


publicProgressRenderer()...{
super();
setOpaque(true);
b.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
}

publicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,

booleanisSelected,booleanhasFocus,introw,intcolumn)...{
Integeri=(Integer)value;
Stringtext="完成";

if(i<0)...{
//删除
text="取消完毕";

}elseif(i<100)...{
b.setValue(i);
returnb;
}
super.getTableCellRendererComponent(table,text,isSelected,hasFocus,
row,column);
returnthis;
}
}
MyPanel.java
packageorg.loon.test;

importjava.awt.BorderLayout;
importjava.awt.Color;
importjava.awt.Component;
importjava.awt.Dimension;
importjava.awt.EventQueue;
importjava.awt.event.ActionEvent;
importjava.util.HashSet;
importjava.util.Random;

importjavax.swing.AbstractAction;
importjavax.swing.Action;
importjavax.swing.Icon;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
importjavax.swing.JPopupMenu;
importjavax.swing.JScrollPane;
importjavax.swing.JSeparator;
importjavax.swing.JTable;
importjavax.swing.RowFilter;
importjavax.swing.SwingWorker;
importjavax.swing.WindowConstants;
importjavax.swing.table.TableCellRenderer;
importjavax.swing.table.TableColumn;
importjavax.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>
*
*@authorchenpeng
*@email:[email protected]
*@version0.1
*/

publicclassMyPanelextendsJPanel...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;

privatestaticfinalColorevenColor=newColor(250,250,250);

privatefinalMyTableModelmodel=newMyTableModel();

privatefinalTableRowSorter<MyTableModel>sorter=newTableRowSorter<MyTableModel>(
model);

privatefinalJTabletable;


publicMyPanel()...{
super(newBorderLayout());

table=newJTable(model)...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;

publicComponentprepareRenderer(

TableCellRenderertableCellRenderer,introw,intcolumn)...{
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());
}
returncomponent;
}


publicJPopupMenugetComponentPopupMenu()...{
returnmakePopup();
}
};
table.setRowSorter(sorter);
model.addTest(newTest("进度条测试",100),null);

//滚动条
JScrollPanescrollPane=newJScrollPane(table);
//背景色
scrollPane.getViewport().setBackground(Color.black);
//弹出菜单
table.setComponentPopupMenu(newJPopupMenu());
//是否始终大到足以填充封闭视口的高度
table.setFillsViewportHeight(true);
//将单元格间距的高度和宽度设置为指定的Dimension
table.setIntercellSpacing(newDimension());
//是否绘制单元格间的水平线
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(newProgressRenderer());

//添加按钮
add(newJButton(newCreateNewAction("添加",null)),BorderLayout.SOUTH);
add(scrollPane,BorderLayout.CENTER);
setPreferredSize(newDimension(320,180));
}


classCreateNewActionextendsAbstractAction...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;


publicCreateNewAction(Stringlabel,Iconicon)...{
super(label,icon);
}


publicvoidactionPerformed(ActionEventevt)...{
createNewActionPerformed(evt);
}
}


/***//**
*创建事件
*@paramevt
*/

privatevoidcreateNewActionPerformed(ActionEventevt)...{
finalintkey=model.getRowCount();
//在jdk1.6后,当一个Swing程序需要执行一个多线程任务时,可以通过javax.swing.SwingWorker实例进行实现。
//SwingWorker的process可以定义约束属性。更改这些属性将触发事件,并从事件调度线程上引起事件处理方法的调用。
//SwingWorker的done方法,在后台任务完成时自动的在事件调度线程上被调用。

SwingWorker<Integer,Integer>worker=newSwingWorker<Integer,Integer>()...{
//随机sleep
privateintsleepDummy=newRandom().nextInt(100)+1;

//最大任务数量
privateinttaskSize=200;


protectedIntegerdoInBackground()...{
intcurrent=0;

while(current<taskSize&&!isCancelled())...{
current++;

try...{
Thread.sleep(sleepDummy);

}catch(InterruptedExceptionie)...{
publish(-1);
break;
}
publish(100*current/taskSize);
}
returnsleepDummy*taskSize;
}


/***//**
*进行中处理
*/

protectedvoidprocess(java.util.List<Integer>data)...{

for(Integervalue:data)...{
//把数据填入对应的行列
model.setValueAt(value,key,2);
}
//传送变更事件给指定行列
model.fireTableCellUpdated(key,2);
}


/***//**
*完成后处理
*/

protectedvoiddone()...{
}
};
model.addTest(newTest("进度条测试",0),worker);
worker.execute();
}


classCancelActionextendsAbstractAction...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;


publicCancelAction(Stringlabel,Iconicon)...{
super(label,icon);
}


publicvoidactionPerformed(ActionEventevt)...{
cancelActionPerformed(evt);
}
}


/***//**
*取消进度
*@paramevt
*/

publicsynchronizedvoidcancelActionPerformed(ActionEventevt)...{
int[]selection=table.getSelectedRows();
if(selection==null||selection.length<=0)
return;

for(inti=0;i<selection.length;i++)...{
intmidx=table.convertRowIndexToModel(selection[i]);
SwingWorkerworker=model.getSwingWorker(midx);

if(worker!=null&&!worker.isDone())...{
worker.cancel(true);
}
worker=null;
}
table.repaint();
}


/***//**
*取消下载进程
*
*@authorchenpeng
*
*/

classDeleteActionextendsAbstractAction...{

/***//**
*
*/
privatestaticfinallongserialVersionUID=1L;


publicDeleteAction(Stringlabel,Iconicon)...{
super(label,icon);
}


publicvoidactionPerformed(ActionEventevt)...{
deleteActionPerformed(evt);
}
}

privatefinalHashSet<Integer>set=newHashSet<Integer>();


publicsynchronizedvoiddeleteActionPerformed(ActionEventevt)...{
int[]selection=table.getSelectedRows();
if(selection==null||selection.length<=0)
return;

for(inti=0;i<selection.length;i++)...{
intmidx=table.convertRowIndexToModel(selection[i]);
set.add(midx);
SwingWorkerworker=model.getSwingWorker(midx);

if(worker!=null&&!worker.isDone())...{
worker.cancel(true);
}
worker=null;
}
//JTable过滤器

finalRowFilter<MyTableModel,Integer>filter=newRowFilter<MyTableModel,Integer>()...{

publicbooleaninclude(

Entry<?extendsMyTableModel,?extendsInteger>entry)...{
Integermidx=entry.getIdentifier();
return!set.contains(midx);
}
};
sorter.setRowFilter(filter);
table.repaint();
}


privateJPopupMenumakePopup()...{
JPopupMenupop=newJPopupMenu();
Actionact=newCreateNewAction("添加",null);
pop.add(act);
act=newCancelAction("取消",null);
int[]selection=table.getSelectedRows();
if(selection==null||selection.length<=0)
act.setEnabled(false);
pop.add(act);
//分割线
pop.add(newJSeparator());
act=newDeleteAction("删除",null);
if(selection==null||selection.length<=0)
act.setEnabled(false);
pop.add(act);
returnpop;
}


publicstaticvoidmain(String[]args)...{

EventQueue.invokeLater(newRunnable()...{

publicvoidrun()...{
createGUI();
}
});
}


publicstaticvoidcreateGUI()...{

JFrameframe=newJFrame("在JTable中加载进度条及进行操作");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(newMyPanel());
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
运行效果如下: