且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

将进度条添加到每个表单元格以进行文件进度 - Java

更新时间:2023-12-02 22:35:16

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



免责声明:这是一个例子。我使用一个 Thread.sleep 可以稍微减慢读数,忽略缓冲区和其他一些我在生产代码中的不同之处,但我想强调进度更新。





工作原理



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



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



最后,通知表对模型的更改,以便它会自动重绘。

  public class UpdateTable {

public static void main(String [] args){
new UpdateTable();
}

public UpdateTable(){
EventQueue.invokeLater(new Runnable(){
@Override
public void run(){
尝试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex){
}

UpdatableTableModel模型= 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));
fra me.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);
返回这个;
}
}

public class RowData {

private File file;
private String type;
私人长度;
私人浮动状态;

public RowData(文件文件,字符串类型){
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< RowData>行;
private Map< File,RowData> mapLookup;

public UpdatableTableModel(){
rows = new ArrayList 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;
案例1:
name =文件类型;
break;
case 2:
name =Size;
break;
案例3:
name =状态;
break;
}
返回名称;
}

@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;
}
返回值;
}

@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扩展SwingWorker< List< File>,File> {

private UpdatableTableModel模型;

public FileFinderWorker(UpdatableTableModel model){
this.model = model;
}

@Override
protected void process(List< File> chunks){
for(File file:chunks){
model.addFile文件);
}
}

@Override
protected List< File> doInBackground()throws Exception {
文件文件[] = new File(System.getProperty(user.dir))。listFiles();
列表<文件> lstFiles = new ArrayList(Arrays.asList(files));
(文件文件:lstFiles){
//你实际上可以发布整个数组,但我正在做这个
//故意;)
publish(file);
}
return lstFiles;
}

@Override
protected void done(){
try {
列表<文件> files = get();
(文件文件:文件){
new FileReaderWorker(model,file).execute();
}
} catch(Exception exp){
exp.printStackTrace();
}
}
}

public class FileReaderWorker扩展SwingWorker< File,File> {

private File currentFile;
private UpdatableTableModel模型;

public FileReaderWorker(UpdatableTableModel模型,文件文件){
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;
}
}
}

重要概念。 >

从来没有,EVER通过任何长时间运行的操作阻止事件调度线程。相反,将这些耗时的操作移动到后台线程中。在这里,我使用了 SwingWorker



阅读 Swing中的并发更多信息


The application encrypts each file that is put into the table when you click encrypt and I would like to show the progress of the files as they are being encrypted. The "Status" column will then change from "Not Processed" to "Processed."

Similar to the way you watch multiple files attach in an email. I've been looking into the cell renderer and the ProgressBarTablecell but am unsure how to go about implementing them. Any help appreciated. I'm posting the table.

        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();
                        } else {
                            table.setRowSelectionInterval(row, row);
                        }
                        dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
                    }

                    @Override
                    public synchronized void drop(DropTargetDropEvent dtde) {
                        if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
                        {//make sure the flavors are files
                            dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);//dndconstants tells what to do with the drag files
                            //change to ACTION_COPY so it removes the file from the directory
                            Transferable t = dtde.getTransferable();
                            List fileList = null;
                            try {
                                fileList = (List) t.getTransferData(DataFlavor.javaFileListFlavor);//get file
                                if (fileList.size() > 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);
            }
        }
    }

Here is a basic example, this basically uses a SwingWorker to scan the root directory of your drive and lists all the files. Once that's completed, it will attempt to read each file, in it's own SwingWorker updating the table as it goes.

Disclaimer: This is an example. I use a Thread.sleep to slow the reads down slightly, ignore the buffers and a few other things I would do it differently in production code, but I wanted to highlight the progress updates.

How it works

First, you need a cell renderer capable of displaying progress updates. I've chosen a simple custom JProgressBar, but you might like something a little more sophisticated.

You need some way to update the table model. I've chose to provide a simple updateStatus method, passing the file I'm updating, this allows me to use internal look ups to find the row in question. I then use the setValueAt method to update the row object. This is not really required, but I wanted to demonstrate the use of the setValueAt method, you could have updated the row object from the updateStatus method directly.

And finally, notify the table of changes to the model so it will repaint itself.

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<RowData> rows;
        private Map<File, RowData> 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<List<File>, File> {

        private UpdatableTableModel model;

        public FileFinderWorker(UpdatableTableModel model) {
            this.model = model;
        }

        @Override
        protected void process(List<File> chunks) {
            for (File file : chunks) {
                model.addFile(file);
            }
        }

        @Override
        protected List<File> doInBackground() throws Exception {
            File files[] = new File(System.getProperty("user.dir")).listFiles();
            List<File> 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<File> files = get();
                for (File file : files) {
                    new FileReaderWorker(model, file).execute();
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }
    }

    public class FileReaderWorker extends SwingWorker<File, File> {

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

Important concepts.

NEVER, EVER block the Event Dispatching Thread with any kind of long running operation. Instead, move these time consuming operations off into a background thread. Here, I've used SwingWorker

Have a read through Concurrency in Swing for more info