如何搜索子文件夹并使用Java中的新数据重新绘制jTable? [英] How to search subfolders and repaint a jTable with new data in Java?

查看:105
本文介绍了如何搜索子文件夹并使用Java中的新数据重新绘制jTable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序遇到了一些问题。我想让一个jTable显示添加到其TableModel的各种数据点,但我似乎无法使用新数据更新表。



此外,似乎我在目录中搜索png图像的效果不足以完全搜索所有png图像的目录,只停留在第一个文件夹的内容中。



我已经放置了所有png图像数据指向适当的ArrayLists以获取其数据类型,并在将它们放入我的jTable的TableModel之前将它们转换为Object数组。它没有用,我没有用自己的知识解决这些问题。



一些代码:

  private void btnPatchSelActionPerformed(java.awt.event.ActionEvent evt){
fchsFolderChooser.showOpenDialog(null);
File selFile = fchsFolderChooser.getSelectedFile();
fldPatchSel.setText(selFile.getPath());
文件pngs [] = selFile.listFiles(IMAGE_FILTER);
for(File png:pngs){
try {BufferedImage img = ImageIO.read(png);
patchWs.add(img.getWidth()); patchHs.add(img.getHeight());
patchDims.add(img.getWidth()+x+ img.getHeight());
patchImgs.add(img); patchImgPaths.add(png.getPath());
sels.add(false);
System.out.println(Found+ png.getPath());
} catch(IOException e){
System.out.println(Bad image:+ png); e.printStackTrace();
}
}
if(!(fldPatchSel.getText()。endsWith(...)|| fldModSel.getText()。endsWith(...))) {BuildTable();}
}

mod资产选择的对应类似但没有设置sels ArrayList。

  private void BuildTable(){
DefaultTableModel model =(DefaultTableModel)tblImgList.getModel();
Object [] boolSels = sels.toArray();
Object [] stringPatchPaths = patchImgPaths.toArray();
Object [] stringPatchImgDims = patchDims.toArray();
model.addColumn(,boolSels);
model.addColumn(Patch Image,stringPatchPaths);
model.addColumn(W x H,stringPatchImgDims);
tblImgList.repaint();
}

您如何解决我的两个问题?该程序不搜索子文件夹,也无法在表格中显示新数据。

解决方案

首先,删除 DefaultTableModel ,您的数据模型正变得复杂。从POJO(普通旧Java对象)开始,它包含您要显示的内容的上下文...

  public class ImageProperty {

private文件来源;
私人尺寸;选择
私有布尔值;

public ImageProperty(文件来源,尺寸大小,选择布尔值){
this.source = source;
this.size = size;
this.selected =已选中;
}

public Dimension getSize(){
return size;
}

public File getSource(){
return source;
}

public boolean isSelected(){
return selected;
}

}

这包含了所有信息单个图像文件,将用于表示表中行的内容。



其次,创建自定义 TableModel 。这是一种个人的事情,但是使用 DefaultTableModel ,你花费更多时间来破解它,试图让它做你想做的事情,这可以通过使用你的拥有...

 公共类ImageTableModel扩展AbstractTableModel {

private List< ImageProperty>图片;

public ImageTableModel(){
images = new ArrayList< ImageProperty>(25);
}

@Override
public int getRowCount(){
return images.size();
}

@Override
public int getColumnCount(){
return 4;
}

@Override
public String getColumnName(int column){
String name =;
switch(列){
case 1:
name =Path;
休息;
案例2:
name =姓名;
休息;
案例3:
name =Size;
休息;
}
返回名称;
}

@Override
public Class<?> getColumnClass(int columnIndex){
return columnIndex == 0? Boolean.class:String.class;
}

@Override
public Object getValueAt(int rowIndex,int columnIndex){
ImageProperty row = images.get(rowIndex);
Object value = null;
switch(columnIndex){
case 0:
value = row.isSelected();
休息;
case 1:
value = row.getSource()。getParent();
休息;
case 2:
value = row.getSource()。getName();
休息;
case 3:
value = row.getSize()。width +x+ row.getSize()。height;
休息;
}
返回值;
}

public void addImage(ImageProperty image){

images.add(image);
fireTableRowsInserted(images.size() - 1,images.size() - 1);

}

public void addImages(List< ImageProperty> newImages){

int firstRow = images.size();
int lastRow = firstRow + newImages.size() - 1;

images.addAll(newImages);
fireTableRowsInserted(firstRow,lastRow);

}

public void clear(){

int lastRow = images.size()-1;
images.clear();
fireTableRowsDeleted(0,lastRow);

}

}

三,不要尝试在事件调度线程中进行目录扫描,这将导致UI暂停直到扫描完成,并且根据图像的大小和子目录的数量,可能需要几分钟才能完成。 / p>

请参阅了解更多详情


I'm having a couple problems with my program. I wanted a jTable to display various data points added to its TableModel, but I can't seem to get the table to update with the new data.

Also, it seems my search for png images within a directory has fallen short of actually searching the directory completely for all png images and stops only at the first folder's contents.

I've placed all data points into appropriate ArrayLists for their data types and converted them to Object arrays before placing them within the TableModel of my jTable. It's not worked, and I've come short of solving these problems with my own knowledge.

Some code:

private void btnPatchSelActionPerformed(java.awt.event.ActionEvent evt) {                                            
    fchsFolderChooser.showOpenDialog(null);
    File selFile = fchsFolderChooser.getSelectedFile();
    fldPatchSel.setText(selFile.getPath());
    File pngs[] = selFile.listFiles(IMAGE_FILTER);
    for (File png : pngs) {
        try {BufferedImage img = ImageIO.read(png);
            patchWs.add(img.getWidth()); patchHs.add(img.getHeight());
            patchDims.add(img.getWidth() + "x" + img.getHeight());
            patchImgs.add(img); patchImgPaths.add(png.getPath());
            sels.add(false);
            System.out.println("Found " + png.getPath());
        } catch (IOException e) {
            System.out.println("Bad image: " + png); e.printStackTrace();
        }
    }
    if(!(fldPatchSel.getText().endsWith("...")||fldModSel.getText().endsWith("..."))) {BuildTable();}
}

The mod asset selection's counterpart is analogous but without setting the sels ArrayList.

private void BuildTable(){
        DefaultTableModel model = (DefaultTableModel) tblImgList.getModel();
        Object[] boolSels = sels.toArray();
        Object[] stringPatchPaths = patchImgPaths.toArray();
        Object[] stringPatchImgDims = patchDims.toArray();
        model.addColumn("", boolSels);
        model.addColumn("Patch Image", stringPatchPaths);
        model.addColumn("W x H", stringPatchImgDims);
        tblImgList.repaint();
    }

How would you solve my two problems? The program's not searching subfolders and not able to display new data in the table.

解决方案

First, drop the DefaultTableModel, you data model is becoming to complex. Start with a POJO (Plain Old Java Object) which wraps the context of what you want to display...

public class ImageProperty {

    private File source;
    private Dimension size;
    private boolean selected;

    public ImageProperty(File source, Dimension size, boolean selected) {
        this.source = source;
        this.size = size;
        this.selected = selected;
    }

    public Dimension getSize() {
        return size;
    }

    public File getSource() {
        return source;
    }

    public boolean isSelected() {
        return selected;
    }

}

This holds all the information for a single image file and will be used to represent the contents of a row in the table.

Second, create a custom TableModel. This is kind of a personal thing, but with DefaultTableModel, you spend way more time hacking around it trying to get it to do what you want which would be better solved by using your own...

public class ImageTableModel extends AbstractTableModel {

    private List<ImageProperty> images;

    public ImageTableModel() {
        images = new ArrayList<ImageProperty>(25);
    }

    @Override
    public int getRowCount() {
        return images.size();
    }

    @Override
    public int getColumnCount() {
        return 4;
    }

    @Override
    public String getColumnName(int column) {
        String name = "";
        switch (column) {
            case 1:
                name = "Path";
                break;
            case 2:
                name = "Name";
                break;
            case 3:
                name = "Size";
                break;
        }
        return name;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return columnIndex == 0 ? Boolean.class : String.class;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        ImageProperty row = images.get(rowIndex);
        Object value = null;
        switch (columnIndex) {
            case 0:
                value = row.isSelected();
                break;
            case 1:
                value = row.getSource().getParent();
                break;
            case 2:
                value = row.getSource().getName();
                break;
            case 3:
                value = row.getSize().width + "x" + row.getSize().height;
                break;
        }
        return value;
    }

    public void addImage(ImageProperty image) {

        images.add(image);
        fireTableRowsInserted(images.size() - 1, images.size() - 1);

    }

    public void addImages(List<ImageProperty> newImages) {

        int firstRow = images.size();
        int lastRow = firstRow + newImages.size() - 1;

        images.addAll(newImages);
        fireTableRowsInserted(firstRow, lastRow);

    }

    public void clear() {

        int lastRow = images.size() -1;
        images.clear();
        fireTableRowsDeleted(0, lastRow);

    }

}

Third, don't try and do directory scanning in the Event Dispatching Thread, this will cause you UI to "pause" until the scan is complete, and depending on the size of your images and the number of sub directories, could take minutes to complete.

See Concurrency in Swing for more details...

There are any number of ways you might overcome this, but SwingWorker is probably the simplest, as it provides functionality to provide updates back the EDT safely, so you can update the UI without causing further issues...

public class ScanWorker extends SwingWorker<Object, ImageProperty> {

    private File source;
    private ImageTableModel model;

    public ScanWorker(File source, ImageTableModel model) {
        this.source = source;
        this.model = model;
    }

    @Override
    protected void process(List<ImageProperty> chunks) {
        model.addImages(chunks);
    }

    @Override
    protected Object doInBackground() throws Exception {
        scan(source);
        return null;
    }

    protected void scan(File dir) {
        firePropertyChange("directory", dir.getParent(), dir);
        File pngs[] = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().toLowerCase().endsWith(".png");
            }
        });
        for (File png : pngs) {
            try {
                BufferedImage img = ImageIO.read(png);
                publish(new ImageProperty(png, new Dimension(img.getWidth(), img.getHeight()), false));
            } catch (IOException e) {
                System.out.println("Bad image: " + png);
                e.printStackTrace();
            }
        }
        File dirs[] = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        });
        if (dirs != null && dirs.length > 0) {
            for (File subDir : dirs) {
                scan(subDir);
            }
        }
    }

}

This worker uses a recursive method call to scan subdirectories...

And, finally the glue...

This snippet disables the "scan" button, clears the current table model, creates the SwingWorker and registers a PropertyChangeListener to it and finally starts the worker...

model.clear();
scan.setEnabled(false);
ScanWorker worker = new ScanWorker(new File("..."), model);
worker.addPropertyChangeListener(new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("state".equalsIgnoreCase(evt.getPropertyName())) {
            SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
            scan.setEnabled(state == SwingWorker.StateValue.DONE);
            scan.setText("Scan");
        } else if ("directory".equalsIgnoreCase(evt.getPropertyName())) {

            scan.setText(text);

        }
    }
});
worker.execute();

The PropertyChangeListener monitors for changes to the worker's state and resets the button to enabled when it completes. It also monitors for changes to the scanning directory and updates the text of the button to reflect the current directory been processed...nice

The above code snippet is triggered by the ActionListener attached to the "scan" button

And a nice runnable example...

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;

public class ShowImages {

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

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

                final ImageTableModel model = new ImageTableModel();
                JTable table = new JTable(model);

                final JButton scan = new JButton("Scan");
                scan.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        model.clear();
                        scan.setEnabled(false);
                        ScanWorker worker = new ScanWorker(new File("C:\\Users\\shane\\Dropbox\\MegaTokyo"), model);
                        worker.addPropertyChangeListener(new PropertyChangeListener() {
                            @Override
                            public void propertyChange(PropertyChangeEvent evt) {
                                if ("state".equalsIgnoreCase(evt.getPropertyName())) {
                                    SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
                                    scan.setEnabled(state == SwingWorker.StateValue.DONE);
                                    scan.setText("Scan");
                                } else if ("directory".equalsIgnoreCase(evt.getPropertyName())) {

                                    String text = ((File)evt.getNewValue()).getPath().replaceAll("shane", "...");
                                    text = text.replaceAll("C:\\\\", "...");
                                    text = text.replaceAll("Dropbox", "...");
                                    scan.setText(text);

                                }
                            }
                        });
                        worker.execute();
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.add(scan, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ImageProperty {

        private File source;
        private Dimension size;
        private boolean selected;

        public ImageProperty(File source, Dimension size, boolean selected) {
            this.source = source;
            this.size = size;
            this.selected = selected;
        }

        public Dimension getSize() {
            return size;
        }

        public File getSource() {
            return source;
        }

        public boolean isSelected() {
            return selected;
        }

    }

    public class ImageTableModel extends AbstractTableModel {

        private List<ImageProperty> images;

        public ImageTableModel() {
            images = new ArrayList<ImageProperty>(25);
        }

        @Override
        public int getRowCount() {
            return images.size();
        }

        @Override
        public int getColumnCount() {
            return 4;
        }

        @Override
        public String getColumnName(int column) {
            String name = "";
            switch (column) {
                case 1:
                    name = "Path";
                    break;
                case 2:
                    name = "Name";
                    break;
                case 3:
                    name = "Size";
                    break;
            }
            return name;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return columnIndex == 0 ? Boolean.class : String.class;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            ImageProperty row = images.get(rowIndex);
            Object value = null;
            switch (columnIndex) {
                case 0:
                    value = row.isSelected();
                    break;
                case 1:
                    value = row.getSource().getParent();
                    break;
                case 2:
                    value = row.getSource().getName();
                    break;
                case 3:
                    value = row.getSize().width + "x" + row.getSize().height;
                    break;
            }
            return value;
        }

        public void addImage(ImageProperty image) {

            images.add(image);
            fireTableRowsInserted(images.size() - 1, images.size() - 1);

        }

        public void addImages(List<ImageProperty> newImages) {

            int firstRow = images.size();
            int lastRow = firstRow + newImages.size() - 1;

            images.addAll(newImages);
            fireTableRowsInserted(firstRow, lastRow);

        }

        public void clear() {

            int lastRow = images.size() -1;
            images.clear();
            fireTableRowsDeleted(0, lastRow);

        }

    }

    public class ScanWorker extends SwingWorker<Object, ImageProperty> {

        private File source;
        private ImageTableModel model;

        public ScanWorker(File source, ImageTableModel model) {
            this.source = source;
            this.model = model;
        }

        @Override
        protected void process(List<ImageProperty> chunks) {
            model.addImages(chunks);
        }

        @Override
        protected Object doInBackground() throws Exception {
            scan(source);
            return null;
        }

        protected void scan(File dir) {
            firePropertyChange("directory", dir.getParent(), dir);
            File pngs[] = dir.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.getName().toLowerCase().endsWith(".png");
                }
            });
            for (File png : pngs) {
                try {
                    BufferedImage img = ImageIO.read(png);
                    publish(new ImageProperty(png, new Dimension(img.getWidth(), img.getHeight()), false));
                } catch (IOException e) {
                    System.out.println("Bad image: " + png);
                    e.printStackTrace();
                }
            }
            File dirs[] = dir.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.isDirectory();
                }
            });
            if (dirs != null && dirs.length > 0) {
                for (File subDir : dirs) {
                    scan(subDir);
                }
            }
        }

    }

}

Take a look at Worker Threads and SwingWorker for more details

这篇关于如何搜索子文件夹并使用Java中的新数据重新绘制jTable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆