How to change description image in JList java

痴心易碎 提交于 2019-12-11 09:46:27

问题


Below is my code that displays images in a JList. I want to edit the description by each of the images shown in the JList. I don't know how to do it & need help. Thanks...

import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;

public class DesignPicture2 {

    private static String imageName;
    static ArrayList<String> imgName = new ArrayList<String>();

    public static void main(String[] args) throws Exception {
        DesignPicture2 mm = new DesignPicture2();
        mm.getImageName("C:\\Images 2 display");

        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFrame frame = new JFrame("Image panel");
        frame.setSize(800, 500);
        //frame.setLocationByPlatform(true);
        frame.setLocation(600, 300);

        JList imageList = createImageList();

        frame.getContentPane().add(new JScrollPane(imageList));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static JList createImageList() {

        JList imageList = new JList(createModel("C:\\Images 2 display"));
        imageList.setCellRenderer(new ImageCellRenderer());
        imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        imageList.setVisibleRowCount(0);
        imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        imageList.setFixedCellWidth(240);
        imageList.setFixedCellHeight(120);

        // imageList.setDragEnabled(false);
        //imageList.setDropMode(DropMode.INSERT);
        imageList.setTransferHandler(new ImageTransferHandler(imageList));

        return imageList;
    }

    private static DefaultListModel createModel(String path) {

        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        DefaultListModel model = new DefaultListModel();

        int count = 0;
        for (int i = 0; i < listOfFiles.length - 1; i++) {
            System.out.println("check path: " + listOfFiles[i]);
            imageName = imgName.get(i).toString();
            String name = listOfFiles[i].toString();
            //load only JPEGS

            if (name.endsWith("jpg")) {
                try {
                    ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
                    model.add(count, ii);

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        return model;
    }

    static class ImageTransferHandler extends TransferHandler {

        private static final DataFlavor DATA_FLAVOUR = new DataFlavor(ColorIcon.class, "Images");

        private final JList previewList;
        private boolean inDrag;

        ImageTransferHandler(JList previewList) {
            this.previewList = previewList;
        }

        public int getSourceActions(JComponent c) {
            return TransferHandler.MOVE;
        }

        protected Transferable createTransferable(JComponent c) {
            inDrag = true;
            return new Transferable() {
                public DataFlavor[] getTransferDataFlavors() {
                    return new DataFlavor[]{DATA_FLAVOUR};
                }

                public boolean isDataFlavorSupported(DataFlavor flavor) {
                    return flavor.equals(DATA_FLAVOUR);
                }

                public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                    return previewList.getSelectedValue();
                }
            };
        }

        public boolean canImport(TransferSupport support) {
            if (!inDrag || !support.isDataFlavorSupported(DATA_FLAVOUR)) {
                return false;
            }

            JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
            if (dl.getIndex() == -1) {
                return false;
            } else {
                return true;
            }
        }

        public boolean importData(TransferSupport support) {
            if (!canImport(support)) {
                return false;
            }

            Transferable transferable = support.getTransferable();
            try {
                Object draggedImage = transferable.getTransferData(DATA_FLAVOUR);

                JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
                DefaultListModel model = (DefaultListModel) previewList.getModel();
                int dropIndex = dl.getIndex();
                if (model.indexOf(draggedImage) < dropIndex) {
                    dropIndex--;
                }
                model.removeElement(draggedImage);
                model.add(dropIndex, draggedImage);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }

        protected void exportDone(JComponent source, Transferable data, int action) {
            super.exportDone(source, data, action);
            inDrag = false;
        }
    }

    static class ImageCellRenderer extends JPanel implements ListCellRenderer {

        int count = 0;
        DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
        JLabel imageLabel = new JLabel();
        JLabel descriptionLabel = new JLabel();

        ImageCellRenderer() {
            setLayout(new BorderLayout());
            Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
            imageLabel.setBorder(emptyBorder);
            descriptionLabel.setBorder(emptyBorder);
            add(imageLabel, BorderLayout.AFTER_LINE_ENDS);
            add(descriptionLabel, BorderLayout.SOUTH);

            // imageLabel.setText(imgName.get(0).toString());
        }

        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            setBorder(defaultListCellRenderer.getBorder());
            setBackground(defaultListCellRenderer.getBackground());
            imageLabel.setIcon((Icon) value);

            if (count > imgName.size() - 1) {
                count = 0;
            } else {
                descriptionLabel.setText(imgName.get(count).toString());

            }
            return this;
        }

    }

    public void getImageName(String path) {
        int c = 0;
        final File dir = new File(path);

        // array of supported extensions (use a List if you prefer)
        final String[] EXTENSIONS = new String[]{
            "jpg", "gif", "png", "bmp" // and other formats you need
        // filter to identify images based on their extensions
        };
        final FilenameFilter IMAGE_FILTER = new FilenameFilter() {

            @Override
            public boolean accept(final File dir, final String name) {
                for (final String ext : EXTENSIONS) {
                    if (name.endsWith("." + ext)) {
                        return (true);
                    }
                }
                return (false);
            }
        };

        if (dir.isDirectory()) { // make sure it's a directory
            for (final File f : dir.listFiles(IMAGE_FILTER)) {
                BufferedImage img = null;
                c++;
                try {
                    img = ImageIO.read(f);

                    // you probably want something more involved here
                    // to display in your UI
                    System.out.println("image: " + f.getName());
                    imgName.add(f.getName().toString());

                } catch (final IOException e) {
                    // handle errors here
                    System.out.println("Error!");
                }
            }
            System.out.println("C: " + c);
        } else {
            System.out.println("Invalid Directory!");
        }
    }

    static class ColorIcon implements Icon, Serializable {

        private Color color;

        ColorIcon(Color color) {
            this.color = color;
        }

        public void paintIcon(Component c, Graphics g, int x, int y) {
            g.setColor(color);
            g.fillRect(x, y, getIconWidth(), getIconHeight());
        }

        public int getIconWidth() {
            return 200;
        }

        public int getIconHeight() {
            return 100;
        }

        public boolean equals(Object o) {
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            return color.equals(((ColorIcon) o).color);
        }
    }

}

When I run the above code, it show the image in proper way, but the description of each image is fixed and I don't know how to change it. Hope anyone can help me.


回答1:


I agree with trashgod (+1 to his suggestion), a JTable will be a simpler solution, here's why...

JList doesn't support editability, so you'd need to create it...

So, first, we'd need some kind of ListModel that provided some additional functionality, in particular, the ability to set the value at a particular index...

import javax.swing.ListModel;

public interface MutableListModel<E> extends ListModel<E> {

    public void setElementAt(E value, int index);

    public boolean isCellEditable(int index);

}

Next, we'd need some kind editor, in this case, following standard Swing API conventions, this asks for some kind of base interface

import java.awt.Component;
import javax.swing.CellEditor;
import javax.swing.JList;

public interface ListCellEditor<E> extends CellEditor {

    public Component getListCellEditorComponent(
            JList<E> list,
            E value,
            boolean isSelected,
            int index);

    public void applyEditorValue(E value);

}

Now, we need to create ourselves a custom JList capable of actually performing all the required functionality of editing a cell value...

Things like...

  • Recognising a "start editing" event
  • Determine if the cell can be edited
  • Managing the editing process, preparing and showing the editor, knowing when the editor has stopped or canceled and clean up appropriately...
  • Handling selection changes while editing is in progress
  • Handling component focus change (which I've not done cause that's an awesome amount of fun in itself...)

For example...

import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JList;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class EditableList<E> extends JList<E> {

    private ListCellEditor<E> editor;
    private int editingCell = -1;
    private Component editorComponent;

    private CellEditorHandler handler;

    public EditableList(MutableListModel<E> model) {
        this();
        setModel(model);
    }

    public EditableList() {
        InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "editorCell");

        ActionMap am = getActionMap();
        am.put("editorCell", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Edit baby");
                int cell = getSelectedIndex();
                editCellAt(cell);
            }
        });

        addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                if (isEditing()) {

                    if (!stopCellEditing()) {

                        cancelCellEditing();

                    }

                }
            }
        });
    }

    public boolean isEditing() {

        return editorComponent != null;

    }

    public void cancelCellEditing() {

        getEditor().cancelCellEditing();

    }

    public boolean stopCellEditing() {

        return getEditor().stopCellEditing();

    }

    public CellEditorHandler getCellEditorHandler() {
        if (handler == null) {
            handler = new CellEditorHandler();
        }
        return handler;
    }

    public void setEditor(ListCellEditor<E> value) {
        if (value != editor) {
            ListCellEditor old = editor;
            editor = value;
            firePropertyChange("editor", old, editor);
        }
    }

    public ListCellEditor<E> getEditor() {
        return editor;
    }

    public boolean isCellEditable(int cell) {

        boolean isEditable = false;

        ListModel model = getModel();
        if (model instanceof MutableListModel) {

            MutableListModel mcm = (MutableListModel) model;
            isEditable = mcm.isCellEditable(cell);

        }

        return isEditable;

    }

    protected void editCellAt(int index) {

        if (isCellEditable(index)) {

            ListCellEditor<E> editor = getEditor();
            if (editor != null) {

                Rectangle cellBounds = getCellBounds(index, index);
                E value = getModel().getElementAt(index);
                boolean selected = isSelectedIndex(index);
                editingCell = index;

                editor.addCellEditorListener(getCellEditorHandler());
                editorComponent = editor.getListCellEditorComponent(this, value, selected, index);
                editorComponent.setBounds(cellBounds);

                ensureIndexIsVisible(index);

                add(editorComponent);

                revalidate();

            }

        }

    }

    public int getEditingCell() {
        return editingCell;
    }

    protected void editingHasStopped(ListCellEditor editor) {

        editingCell = -1;

        if (editorComponent != null) {
            remove(editorComponent);
        }

        if (editor != null) {

            editor.removeCellEditorListener(getCellEditorHandler());

        }

    }

    public class CellEditorHandler implements CellEditorListener {

        @Override
        public void editingStopped(ChangeEvent e) {

            E value = getModel().getElementAt(getEditingCell());

            getEditor().applyEditorValue(value);
            ((MutableListModel) getModel()).setElementAt(value, getEditingCell());

            editingHasStopped((ListCellEditor)e.getSource());

        }

        @Override
        public void editingCanceled(ChangeEvent e) {

            editingHasStopped((ListCellEditor)e.getSource());

        }

    }

}

Now, having done all that, you will need change the way you've structured your program, instead of using a List and ListModel to manage the descriptions and images separately, you should probably merge the concept into a single, manageable object, for example...

public class ImagePreview {

    private String name;
    private ImageIcon image;

    public ImagePreview(String name, ImageIcon image) {
        this.name = name;
        this.image = image;
    }

    public String getDescription() {
        return name;
    }

    public ImageIcon getImage() {
        return image;
    }

    protected void setDescription(String description) {
        this.name = description;
    }

}

Even if you choose to use a JTable instead, you'll find this easier to manage...

Now we need some way to render and edit these values, to this end, I choose to start with a base component which could display the image and text...

public class ImagePreviewPane extends JPanel {

    private JLabel imageLabel = new JLabel();
    private JLabel descriptionLabel = new JLabel();

    public ImagePreviewPane() {
        setLayout(new BorderLayout());
        Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
        imageLabel.setBorder(emptyBorder);
        descriptionLabel.setBorder(emptyBorder);
        add(imageLabel, BorderLayout.CENTER);
        add(descriptionLabel, BorderLayout.SOUTH);
    }

    protected JLabel getDescriptionLabel() {
        return descriptionLabel;
    }

    protected JLabel getImageLabel() {
        return imageLabel;
    }

    public void setImage(ImageIcon icon) {
        imageLabel.setIcon(icon);
    }

    public void setDescription(String text) {
        descriptionLabel.setText(text);
    }

}

Create an extended version that could handle editing...

public static class ImagePreviewEditorPane extends ImagePreviewPane {

    private JTextField editor;

    public ImagePreviewEditorPane() {
        super();
        editor = new JTextField();
        remove(getDescriptionLabel());
        add(editor, BorderLayout.SOUTH);
    }

    @Override
    public void setDescription(String text) {
        editor.setText(text);
    }

    public String getDescription() {
        return editor.getText();
    }

    public void setImagePreview(ImagePreview preview) {
        setImage(preview.getImage());
        setDescription(preview.getDescription());
    }

    @Override
    public void addNotify() {
        super.addNotify();
        editor.requestFocusInWindow();
    }

}

This is done to try and make it easier to modify the components later...

Next, a ListCellRenderer

public class ImageCellRenderer extends ImagePreviewPane implements ListCellRenderer {

    public ImageCellRenderer() {
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        Color bg = null;
        Color fg = null;

        JList.DropLocation dropLocation = list.getDropLocation();
        if (dropLocation != null
                && !dropLocation.isInsert()
                && dropLocation.getIndex() == index) {

            bg = DefaultLookup.getColor(this, getUI(), "List.dropCellBackground");
            fg = DefaultLookup.getColor(this, getUI(), "List.dropCellForeground");

            isSelected = true;
        }

        if (isSelected) {
            setBackground(bg == null ? list.getSelectionBackground() : bg);
            setForeground(fg == null ? list.getSelectionForeground() : fg);
        } else {
            setBackground(list.getBackground());
            setForeground(list.getForeground());
        }

        if (value instanceof ImagePreview) {
            ImagePreview ip = (ImagePreview) value;
            setImage(ip.getImage());
            setDescription(ip.getDescription());
        } else {
            setImage(null);
            setDescription("??");
        }

        setEnabled(list.isEnabled());
        setFont(list.getFont());

        return this;
    }

}

And editor...

public class ImagePreviewListCellEditor extends AbstactListCellEditor<ImagePreview> {

    private ImagePreviewEditorPane previewPane;

    public ImagePreviewListCellEditor() {
        previewPane = new ImagePreviewEditorPane();
        InputMap im = previewPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "accept");
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");

        ActionMap am = previewPane.getActionMap();
        am.put("accept", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                stopCellEditing();
            }
        });
        am.put("cancel", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                cancelCellEditing();
            }
        });
    }

    public void applyEditorValue(ImagePreview preview) {
        preview.setDescription(previewPane.getDescription());
    }

    @Override
    public Component getListCellEditorComponent(JList<ImagePreview> list, ImagePreview value, boolean isSelected, int index) {

        Color bg = null;
        Color fg = null;

        JList.DropLocation dropLocation = list.getDropLocation();
        if (dropLocation != null
                && !dropLocation.isInsert()
                && dropLocation.getIndex() == index) {

            bg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellBackground");
            fg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellForeground");

            isSelected = true;
        }

        if (isSelected) {
            previewPane.setBackground(bg == null ? list.getSelectionBackground() : bg);
            previewPane.setForeground(fg == null ? list.getSelectionForeground() : fg);
        } else {
            previewPane.setBackground(list.getBackground());
            previewPane.setForeground(list.getForeground());
        }

        if (value instanceof ImagePreview) {
            ImagePreview preview = (ImagePreview)value;
            previewPane.setImagePreview(preview);
        } else {
            previewPane.setImagePreview(null);
        }

        return previewPane;
    }

}

And finally, putting it altogether...

public class DesignPicture2 {

    public static void main(String[] args) throws Exception {

        DesignPicture2 mm = new DesignPicture2();

        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JFrame frame = new JFrame("Image panel");
        frame.setSize(800, 500);
        frame.setLocation(600, 300);

        JList imageList = createImageList();

        frame.getContentPane().add(new JScrollPane(imageList));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static JList createImageList() {

        EditableList<ImagePreview> imageList = new EditableList(createModel("..."));
        imageList.setEditor(new ImagePreviewListCellEditor());
        imageList.setCellRenderer(new ImageCellRenderer());
        imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        imageList.setVisibleRowCount(0);
        imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        imageList.setFixedCellWidth(240);
        imageList.setFixedCellHeight(120);

        return imageList;
    }

    private static MutableListModel<ImagePreview> createModel(String path) {

        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        DefaultMutableListModel<ImagePreview> model = new DefaultMutableListModel<>();

        int count = 0;
        for (int i = 0; i < listOfFiles.length - 1; i++) {
            System.out.println("check path: " + listOfFiles[i]);
            String name = listOfFiles[i].toString();

            if (name.endsWith("jpg")) {
                try {
                    ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
                    model.addElement(new ImagePreview(name, ii));

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        return model;
    }
}



回答2:


JList does not support the notion of a cell editor. Instead, use a two-column JTable. Some important points:

  • Your model's isCellEditable() implementation should return true for the description column in order to make it editable.
  • Your model's implementation of getColumnClass() can let the default renderer display your image by returning ImageIcon or Icon .


来源:https://stackoverflow.com/questions/23796471/how-to-change-description-image-in-jlist-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!