向每个表格单元格添加进度条以获取文件进度 – Java

当您单击加密时,应用程序会加密放入表中的每个文件,并且我希望在加密时显示文件的进度。 然后,“状态”列将从“未处理”更改为“已处理”。

与您在电子邮件中查看多个文件附件的方式类似。 我一直在研究单元格渲染器和ProgressBarTablecell,但我不确定如何实现它们。 任何帮助赞赏。 我正在张贴桌子。

import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.io.File; import java.io.IOException; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableModel; public class DropTable { public static void main(String[] args) { new DropTable(); } public DropTable() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager .getSystemLookAndFeelClassName());//get look and feel of whatever OS we're using } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new DropPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class DropPane extends JPanel { /** * */ private static final long serialVersionUID = 1L; private JTable table; private JScrollPane scroll; private DefaultTableModel tm = new DefaultTableModel(new String[] { "File", "File Type", "Size", "Status" }, 0); public DropPane() { table = new JTable(); table.setShowGrid(true); table.setShowHorizontalLines(true); table.setShowVerticalLines(true); table.setGridColor(Color.GRAY); table.setModel(tm); table.setFillsViewportHeight(true); table.setPreferredSize(new Dimension(500, 300)); scroll = new JScrollPane(table); table.setDropTarget(new DropTarget() { @Override public synchronized void dragOver(DropTargetDragEvent dtde) { Point point = dtde.getLocation(); int row = table.rowAtPoint(point); if (row  0) { table.clearSelection(); Point point = dtde.getLocation();//point is (x,y) int row = table.rowAtPoint(point); DefaultTableModel model = (DefaultTableModel) table.getModel(); for (Object value : fileList) { if (value instanceof File) { File f = (File) value; if (row < 0) {//insert rows into the right columns model.addRow(new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});//path under "File" } else { model.insertRow(row, new Object[]{f.getAbsolutePath(), "", f.length(), "", ""});//get size of file row++; } } } } } catch (UnsupportedFlavorException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } else { dtde.rejectDrop(); } } }); add(scroll, BorderLayout.CENTER); } } } 

这是一个基本示例,它基本上使用SwingWorker扫描驱动器的根目录并列出所有文件。 一旦完成,它将尝试读取每个文件,在它自己的SwingWorker更新表格。

免责声明:这是一个例子。 我使用Thread.sleep来减慢读取速度,忽略缓冲区和其他一些我会在生产代码中做不同的事情,但我想突出显示进度更新。

在此处输入图像描述

怎么运行的

首先,您需要一个能够显示进度更新的单元格渲染器。 我选择了一个简单的自定义JProgressBar ,但你可能会喜欢一些更复杂的东西。

您需要一些方法来更新表模型。 我选择提供一个简单的updateStatus方法,传递我正在更新的文件,这允许我使用内部查找来查找有问题的行。 然后我使用setValueAt方法更新行对象。 这不是真的需要,但我想演示使用setValueAt方法,您可以直接从updateStatus方法更新行对象。

最后,通知表格模型的更改,以便重新绘制自己。

 public class UpdateTable { public static void main(String[] args) { new UpdateTable(); } public UpdateTable() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } UpdatableTableModel model = new UpdatableTableModel(); JTable table = new JTable(); table.setModel(model); table.getColumn("Status").setCellRenderer(new ProgressCellRender()); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new JScrollPane(table)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); FileFinderWorker worker = new FileFinderWorker(model); worker.execute(); } }); } public class ProgressCellRender extends JProgressBar implements TableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { int progress = 0; if (value instanceof Float) { progress = Math.round(((Float) value) * 100f); } else if (value instanceof Integer) { progress = (int) value; } setValue(progress); return this; } } public class RowData { private File file; private String type; private long length; private float status; public RowData(File file, String type) { this.file = file; this.type = type; this.length = file.length(); this.status = 0f; } public File getFile() { return file; } public long getLength() { return length; } public float getStatus() { return status; } public String getType() { return type; } public void setStatus(float status) { this.status = status; } } public class UpdatableTableModel extends AbstractTableModel { private List rows; private Map mapLookup; public UpdatableTableModel() { rows = new ArrayList<>(25); mapLookup = new HashMap<>(25); } @Override public int getRowCount() { return rows.size(); } @Override public int getColumnCount() { return 4; } @Override public String getColumnName(int column) { String name = "??"; switch (column) { case 0: name = "File"; break; case 1: name = "File Type"; break; case 2: name = "Size"; break; case 3: name = "Status"; break; } return name; } @Override public Object getValueAt(int rowIndex, int columnIndex) { RowData rowData = rows.get(rowIndex); Object value = null; switch (columnIndex) { case 0: value = rowData.getFile(); break; case 1: value = rowData.getType(); break; case 2: value = rowData.getLength(); break; case 3: value = rowData.getStatus(); break; } return value; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { RowData rowData = rows.get(rowIndex); switch (columnIndex) { case 3: if (aValue instanceof Float) { rowData.setStatus((float) aValue); } break; } } public void addFile(File file) { RowData rowData = new RowData(file, "A File"); mapLookup.put(file, rowData); rows.add(rowData); fireTableRowsInserted(rows.size() - 1, rows.size() - 1); } protected void updateStatus(File file, int progress) { RowData rowData = mapLookup.get(file); if (rowData != null) { int row = rows.indexOf(rowData); float p = (float) progress / 100f; setValueAt(p, row, 3); fireTableCellUpdated(row, 3); } } } public class FileFinderWorker extends SwingWorker, File> { private UpdatableTableModel model; public FileFinderWorker(UpdatableTableModel model) { this.model = model; } @Override protected void process(List chunks) { for (File file : chunks) { model.addFile(file); } } @Override protected List doInBackground() throws Exception { File files[] = new File(System.getProperty("user.dir")).listFiles(); List lstFiles = new ArrayList<>(Arrays.asList(files)); for (File file : lstFiles) { // You could actually publish the entire array, but I'm doing this // deliberatly ;) publish(file); } return lstFiles; } @Override protected void done() { try { List files = get(); for (File file : files) { new FileReaderWorker(model, file).execute(); } } catch (Exception exp) { exp.printStackTrace(); } } } public class FileReaderWorker extends SwingWorker { private File currentFile; private UpdatableTableModel model; public FileReaderWorker(UpdatableTableModel model, File file) { this.currentFile = file; this.model = model; addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("progress")) { FileReaderWorker.this.model.updateStatus(currentFile, (int) evt.getNewValue()); } } }); } @Override protected File doInBackground() throws Exception { if (currentFile.isFile()) { setProgress(0); long fileLength = currentFile.length(); BufferedReader reader = null; char[] cbuf = new char[1024]; try { reader = new BufferedReader(new FileReader(currentFile)); int bytesRead = -1; int totalBytesRead = 0; while ((bytesRead = reader.read(cbuf)) != -1) { totalBytesRead += bytesRead; int progress = (int) Math.round(((double) totalBytesRead / (double) fileLength) * 100d); setProgress(progress); Thread.sleep(25); } setProgress(100); } catch (Exception e) { e.printStackTrace(); setProgress(100); } finally { try { reader.close(); } catch (Exception e) { } } } else { setProgress(100); } return currentFile; } } } 

重要的概念。

永远不会,使用任何类型的长时间运行操作阻止事件调度线程。 相反,将这些耗时的操作移到后台线程中。 在这里,我使用过SwingWorker

阅读Swing中的Concurrency以获取更多信息

你需要一个包含JProgressBarTableCellRenderer ,如下所示。 您可以从SwingWorker更新每个文件的进度,如此处所示。

图片

您需要使用0到100之间的整数值进行某种处理。例如:

 class Process { public Process(String name, int progress, String description) { super(); this.name = name; this.progress = progress; this.description = description; } String name; int progress; String description; } 

这在表tableModel中建模。

需要渲染器才能在其中一个表列上返回进度条:

 class ProgressRenderer extends DefaultTableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row2, int column) { int row = table.convertRowIndexToModel(row2); ProcessTableModel mtm = (ProcessTableModel) table.getModel(); Process p = (Process) mtm.getProcessAt(row); JProgressBar bar = new JProgressBar(); bar.setValue(p.progress); return bar; } } 

现在,您只需要一个线程即可在后台执行某些操作并更新过程对象。 我可以在这里找到完整的示例,我已经复制了代码片段。

在此处输入图像描述