Drag and drop image with TransferHandler

℡╲_俬逩灬. 提交于 2019-12-24 11:48:03

问题


I am trying to make simple java app to drag and drop image into JLabel which is on JFrame with no luck. I will later use this functionality in my program which will receive dropped image, resize it and then adjust brightness. What is simplest way to make it and to save that image for further editing?

Here is my code which only receives dropped text:

import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.TransferHandler;

class DragNDrop extends JFrame {
        JLabel label;

        public DragNDrop() {

            setTitle("Simple Drag & Drop");
            setLayout(null);

            label = new JLabel();
            label.setBounds(0, 0, 200, 200);

            add(label);
            label.setTransferHandler(new TransferHandler("text"));

            setSize(200, 200);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setVisible(true);
    }

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

回答1:


When you create a TransferHandler using the constructor that takes a String, you create a TransferHandler that can only perform transfers within the same JVM.

new TransferHandler("text") creates a TransferHandler that transfers the 'text' property of JLabel (or any other component or bean). If you want to drag images, you need a property of type Image. JLabel has no properties of type Image, but it has a property of type Icon. If you use that, the drag source must supply data of type Icon, and you will still have the limitation of only accepting data from the same JVM.

If you want to accept any Image data from any application, you must write a custom TransferHandler. Images can take a number of forms, but some common forms are:

  1. A java.awt.Image, represented by DataFlavor.imageFlavor.
  2. A List of Files (List<File>), represented by DataFlavor.javaFileListFlavor. As the name suggests, this usually is the result of the user's dragging files.
  3. Binary data (usually in the form of an InputStream) whose MIME type (such as "image/png") indicates the bytes are an image.

Your custom TransferHandler, then, might look like this:

private static class ImageHandler
extends TransferHandler {
    private static final long serialVersionUID = 1;

    private boolean isReadableByImageIO(DataFlavor flavor) {
        Iterator<?> readers = ImageIO.getImageReadersByMIMEType(
            flavor.getMimeType());
        if (readers.hasNext()) {
            Class<?> cls = flavor.getRepresentationClass();
            return (InputStream.class.isAssignableFrom(cls) ||
                    URL.class.isAssignableFrom(cls) ||
                    File.class.isAssignableFrom(cls));
        }

        return false;
    }

    @Override
    public boolean canImport(TransferSupport support) {
        if (support.getUserDropAction() == LINK) {
            return false;
        }

        for (DataFlavor flavor : support.getDataFlavors()) {
            if (flavor.equals(DataFlavor.imageFlavor) ||
                flavor.equals(DataFlavor.javaFileListFlavor) ||
                isReadableByImageIO(flavor)) {

                return true;
            }
        }
        return false;
    }

    @Override
    public boolean importData(TransferSupport support) {
        if (!(support.getComponent() instanceof JLabel)) {
            return false;
        }
        if (!canImport(support)) {
            return false;
        }

        // There are three types of DataFlavor to check:
        // 1. A java.awt.Image object (DataFlavor.imageFlavor)
        // 2. A List<File> object (DataFlavor.javaFileListFlavor)
        // 3. Binary data with an image/* MIME type.

        if (support.isDataFlavorSupported(DataFlavor.imageFlavor)) {
            try {
                Image image = (Image)
                    support.getTransferable().getTransferData(
                        DataFlavor.imageFlavor);

                JLabel label = (JLabel) support.getComponent();
                label.setIcon(new ImageIcon(image));
                return true;
            } catch (UnsupportedFlavorException | IOException e) {
                e.printStackTrace();
            }
        }

        if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            try {
                Iterable<?> list = (Iterable<?>)
                    support.getTransferable().getTransferData(
                        DataFlavor.javaFileListFlavor);
                Iterator<?> files = list.iterator();
                if (files.hasNext()) {
                    File file = (File) files.next();
                    Image image = ImageIO.read(file);

                    JLabel label = (JLabel) support.getComponent();
                    label.setIcon(new ImageIcon(image));
                    return true;
                }
            } catch (UnsupportedFlavorException | IOException e) {
                e.printStackTrace();
            }
        }

        for (DataFlavor flavor : support.getDataFlavors()) {
            if (isReadableByImageIO(flavor)) {
                try {
                    Image image;

                    Object data =
                        support.getTransferable().getTransferData(flavor);
                    if (data instanceof URL) {
                        image = ImageIO.read((URL) data);
                    } else if (data instanceof File) {
                        image = ImageIO.read((File) data);
                    } else {
                        image = ImageIO.read((InputStream) data);
                    }

                    JLabel label = (JLabel) support.getComponent();
                    label.setIcon(new ImageIcon(image));
                    return true;
                } catch (UnsupportedFlavorException | IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return false;
    }
}

Some additional advice: In practice, when writing a full-featured application, you should be using LayoutManagers. You could remove the setLayout(null) and label.setBounds lines from your code, and you would get exactly the same result, because a JFrame's default contentPane uses a BorderLayout, and the single-argument add method places your JLabel in the center of that BorderLayout, which means it fills the entire frame.



来源:https://stackoverflow.com/questions/20595425/drag-and-drop-image-with-transferhandler

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