aggiunta barra di avanzamento a ogni cella della tabella per l’avanzamento del file – Java

L’applicazione crittografa ogni file che viene inserito nella tabella quando si fa clic su criptare e vorrei mostrare l’avanzamento dei file mentre vengono crittografati. La colonna “Stato” cambierà da “Non elaborato” a “Elaborato”.

Simile al modo in cui guardi più file allegati in un’email. Ho esaminato il rendering delle celle e il ProgressBarTablecell, ma non sono sicuro su come implementarli. Qualsiasi aiuto apprezzato. Sto postando il tavolo.

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); } } } 

Ecco un esempio di base, in pratica utilizza SwingWorker per eseguire la scansione della directory principale dell’unità e elenca tutti i file. Una volta completato, cercherà di leggere ogni file, nel proprio SwingWorker aggiornando la tabella man mano che procede.

Disclaimer: questo è un esempio. Io uso un Thread.sleep per rallentare leggermente le letture, ignorare i buffer e alcune altre cose lo farei in modo diverso nel codice di produzione, ma volevo evidenziare gli aggiornamenti di avanzamento.

inserisci la descrizione dell'immagine qui

Come funziona

Innanzitutto, è necessario un renderer di celle in grado di visualizzare aggiornamenti di avanzamento. Ho scelto una semplice JProgressBar personalizzata, ma ti potrebbe piacere qualcosa di un po ‘più sofisticato.

Hai bisogno di un modo per aggiornare il modello di tabella. Ho scelto di fornire un metodo updateStatus semplice, passando il file che sto aggiornando, questo mi consente di utilizzare le updateStatus interne per trovare la riga in questione. Quindi utilizzo il metodo setValueAt per aggiornare l’object riga. Questo non è realmente necessario, ma volevo dimostrare l’uso del metodo setValueAt , avresti potuto aggiornare direttamente l’object riga dal metodo updateStatus .

Infine, notificare la tabella delle modifiche al modello in modo da ridisegnare se stesso.

 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; } } } 

Concetti importanti

MAI, MAI bloccare il thread di invio eventi con qualsiasi tipo di operazione a lungo termine. Invece, sposta queste operazioni che richiedono molto tempo in un thread in background. Ecco, ho usato SwingWorker

Leggi una recensione su Concorrenza in Swing per maggiori informazioni

Avrai bisogno di un TableCellRenderer che contenga un JProgressBar , come mostrato qui . Puoi aggiornare i progressi di ogni file da un SwingWorker , visto qui .

Immagine

Devi avere un qualche tipo di processo con un valore intero compreso tra 0 e 100. Ad esempio:

 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; } 

Questo viene modellato nella tabella tableModel.

Un renderer è necessario per restituire una barra di avanzamento su una delle colonne delle tabelle:

 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; } } 

Ora hai solo bisogno di un thread per fare qualcosa in background e aggiornare gli oggetti del processo. L’esempio completo, di cui ho copiato frammenti di codice, può essere trovato qui .

inserisci la descrizione dell'immagine qui