setDragImage无法正常工作 - Java 7

时间:2012-07-11 16:43:14

标签: java swing drag-and-drop

我正在尝试设置代码,以便用户可以从JTable拖动到JList,并使用TransferHandler中的Java 7函数setDragImage自定义拖动图像。我在java教程网站上抓了一个例子,他们讲授Drag n Drop,然后添加了一个“setDragImage”代码。但它不起作用。请参阅下面的代码,并在importData函数中找到setDragImage()行。为什么这不起作用?

/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 */

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.awt.datatransfer.*;
import java.awt.image.BufferedImage;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.tree.*;
import javax.swing.table.*;

public class BasicDND extends JPanel implements ActionListener {
    private static JFrame frame;
    private JTextArea textArea;
    private JTextField textField;
    private JList list;
    private JTable table;
    private JTree tree;
    private JColorChooser colorChooser;
    private JCheckBox toggleDnD;

    public BasicDND() {
        super(new BorderLayout());
        JPanel leftPanel = createVerticalBoxPanel();
        JPanel rightPanel = createVerticalBoxPanel();

        //Create a table model.
        DefaultTableModel tm = new DefaultTableModel();
        tm.addColumn("Column 0");
        tm.addColumn("Column 1");
        tm.addColumn("Column 2");
        tm.addColumn("Column 3");
        tm.addRow(new String[]{"Table 00", "Table 01", "Table 02", "Table 03"});
        tm.addRow(new String[]{"Table 10", "Table 11", "Table 12", "Table 13"});
        tm.addRow(new String[]{"Table 20", "Table 21", "Table 22", "Table 23"});
        tm.addRow(new String[]{"Table 30", "Table 31", "Table 32", "Table 33"});

        //LEFT COLUMN
        //Use the table model to create a table.
        table = new JTable(tm);
        leftPanel.add(createPanelForComponent(table, "JTable"));

        //Create a color chooser.
        colorChooser = new JColorChooser();
        leftPanel.add(createPanelForComponent(colorChooser, "JColorChooser"));

        //RIGHT COLUMN
        //Create a textfield.
        textField = new JTextField(30);
        textField.setText("Favorite foods:\nPizza, Moussaka, Pot roast");
        rightPanel.add(createPanelForComponent(textField, "JTextField"));

        //Create a scrolled text area.
        textArea = new JTextArea(5, 30);
        textArea.setText("Favorite shows:\nBuffy, Alias, Angel");
        JScrollPane scrollPane = new JScrollPane(textArea);
        rightPanel.add(createPanelForComponent(scrollPane, "JTextArea"));

        //Create a list model and a list.
        DefaultListModel listModel = new DefaultListModel();
        listModel.addElement("Martha Washington");
        listModel.addElement("Abigail Adams");
        listModel.addElement("Martha Randolph");
        listModel.addElement("Dolley Madison");
        listModel.addElement("Elizabeth Monroe");
        listModel.addElement("Louisa Adams");
        listModel.addElement("Emily Donelson");
        list = new JList(listModel);
        list.setVisibleRowCount(-1);
        list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

        list.setTransferHandler(new TransferHandler() {

            public Image getDragImage() {
                return null;
            }

            @Override
            public boolean canImport(TransferHandler.TransferSupport info) {
                // we only import Strings
                if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    return false;
                }

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

            public BufferedImage makeImageFromString(String s) {
                int width = 100;
                int height = 40;
                BufferedImage br = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
                Graphics g = br.getGraphics();
                g.drawString(s, 0, 0);
                //g.fillRect(0, 0, width, height);
                System.out.println("made image from " + s);
                return br;
            }

            @Override
            public boolean importData(TransferHandler.TransferSupport info) {
                if (!info.isDrop()) {
                    return false;
                }

                // Check for String flavor
                if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    displayDropLocation("List doesn't accept a drop of this type.");
                    return false;
                }

                JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
                DefaultListModel listModel = (DefaultListModel)list.getModel();
                int index = dl.getIndex();
                boolean insert = dl.isInsert();
                // Get the current string under the drop.
                String value = (String)listModel.getElementAt(index);

                // Get the string that is being dropped.
                Transferable t = info.getTransferable();
                String data;
                try {
                    data = (String)t.getTransferData(DataFlavor.stringFlavor);
                } 
                catch (Exception e) { return false; }

                //HERE IS THE CODE TO SET THE DRAG IMAGE
                this.setDragImage(makeImageFromString(data));

                // Display a dialog with the drop information.
                String dropValue = "\"" + data + "\" dropped ";
                if (dl.isInsert()) {
                    if (dl.getIndex() == 0) {
                        displayDropLocation(dropValue + "at beginning of list");
                    } else if (dl.getIndex() >= list.getModel().getSize()) {
                        displayDropLocation(dropValue + "at end of list");
                    } else {
                        String value1 = (String)list.getModel().getElementAt(dl.getIndex() - 1);
                        String value2 = (String)list.getModel().getElementAt(dl.getIndex());
                        displayDropLocation(dropValue + "between \"" + value1 + "\" and \"" + value2 + "\"");
                    }
                } else {
                    displayDropLocation(dropValue + "on top of " + "\"" + value + "\"");
                }

        /**  This is commented out for the basicdemo.html tutorial page.
                 **  If you add this code snippet back and delete the
                 **  "return false;" line, the list will accept drops
                 **  of type string.
                // Perform the actual import.  
                if (insert) {
                    listModel.add(index, data);
                } else {
                    listModel.set(index, data);
                }
                return true;
        */
        return false;
            }

            @Override
            public int getSourceActions(JComponent c) {
                return COPY;
            }

            @Override
            protected Transferable createTransferable(JComponent c) {
                JList list = (JList)c;
                Object[] values = list.getSelectedValues();

                StringBuffer buff = new StringBuffer();

                for (int i = 0; i < values.length; i++) {
                    Object val = values[i];
                    buff.append(val == null ? "" : val.toString());
                    if (i != values.length - 1) {
                        buff.append("\n");
                    }
                }
                return new StringSelection(buff.toString());
            }
        });
        list.setDropMode(DropMode.ON_OR_INSERT);

        JScrollPane listView = new JScrollPane(list);
        listView.setPreferredSize(new Dimension(300, 100));
        rightPanel.add(createPanelForComponent(listView, "JList"));

        //Create a tree.
        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Mia Familia");
        DefaultMutableTreeNode sharon = new DefaultMutableTreeNode("Sharon");
        rootNode.add(sharon);
        DefaultMutableTreeNode maya = new DefaultMutableTreeNode("Maya");
        sharon.add(maya);
        DefaultMutableTreeNode anya = new DefaultMutableTreeNode("Anya");
        sharon.add(anya);
        sharon.add(new DefaultMutableTreeNode("Bongo"));
        maya.add(new DefaultMutableTreeNode("Muffin"));
        anya.add(new DefaultMutableTreeNode("Winky"));
        DefaultTreeModel model = new DefaultTreeModel(rootNode);
        tree = new JTree(model);
        tree.getSelectionModel().setSelectionMode
              (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
        JScrollPane treeView = new JScrollPane(tree);
        treeView.setPreferredSize(new Dimension(300, 100));
        rightPanel.add(createPanelForComponent(treeView, "JTree"));

        //Create the toggle button.
        toggleDnD = new JCheckBox("Turn on Drag and Drop");
        toggleDnD.setActionCommand("toggleDnD");
        toggleDnD.addActionListener(this);

        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                                              leftPanel, rightPanel);
        splitPane.setOneTouchExpandable(true);

        add(splitPane, BorderLayout.CENTER);
        add(toggleDnD, BorderLayout.PAGE_END);
        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    }

    protected JPanel createVerticalBoxPanel() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
        p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        return p;
    }

    public JPanel createPanelForComponent(JComponent comp,
                                          String title) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(comp, BorderLayout.CENTER);
        if (title != null) {
            panel.setBorder(BorderFactory.createTitledBorder(title));
        }
        return panel;
    }

    private void displayDropLocation(final String string) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(null, string);
            }
        });
    }

    public void actionPerformed(ActionEvent e) {
        if ("toggleDnD".equals(e.getActionCommand())) {
            boolean toggle = toggleDnD.isSelected();
            textArea.setDragEnabled(toggle);
            textField.setDragEnabled(toggle);
            list.setDragEnabled(toggle);
            table.setDragEnabled(toggle);
            tree.setDragEnabled(toggle);
            colorChooser.setDragEnabled(toggle);
        }
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        frame = new JFrame("BasicDnD");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new BasicDND();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal's use of bold fonts
            UIManager.put("swing.boldMetal", Boolean.FALSE);
                createAndShowGUI();
            }
        });
    }
}

2 个答案:

答案 0 :(得分:6)

  1. 正如kleopatra所说,删除getDragImage(){return null; }
  2. 将TransferHandler#setDragImage(...)从importData(...)移至getSourceActions(...)
  3. 修复你的makeImageFromString(...)

  4. //As kleopatra says,
    //public Image getDragImage() {
    //    return null;
    //}
    public boolean importData(TransferHandler.TransferSupport info) {
        //...
        //HERE IS THE CODE TO SET THE DRAG IMAGE
        //XXX: this.setDragImage(makeImageFromString(data));
        //...
    }
    @Override public int getSourceActions(JComponent c) {
      System.out.println("getSourceActions");
      this.setDragImage(makeImageFromString(c));
      return COPY;
    }
    
    FontRenderContext frc = new FontRenderContext(null, true, true);
    JPanel p = new JPanel();
    public BufferedImage makeImageFromString(JComponent c) {
      int width = 100;
      int height = 40;
      BufferedImage br = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
      Graphics g = br.getGraphics();
      g.setColor(Color.RED);
      g.fillRect(0, 0, width, height);
    
    //*
      JList l = (JList)c;
      ListCellRenderer r = l.getCellRenderer();
      Component comp = r.getListCellRendererComponent(
          l, l.getSelectedValue(), l.getSelectedIndex(), false, false);
      SwingUtilities.paintComponent(g, comp, p, 0, 0, width, height);
    /*/
      String s = "aaaa";
      Rectangle rect = c.getFont().getStringBounds(s, frc).getBounds();
      int tx = (width  - rect.width)/2  - rect.x;
      int ty = (height - rect.height)/2 - rect.y;
      g.setColor(Color.BLACK);
      g.drawString(s, tx, ty);
      System.out.println("made image from " + s);
    //*/
      g.dispose();
      return br;
    }
    

    注意:TransferHandler#setDragImage(java.awt.Image) (Java Platform SE 7 )


    添加SSCCE:如何使用TransferHandler #setDragImage(...)方法。

    enter image description here

    import java.util.*;
    import java.awt.*;
    import java.awt.image.*;
    import java.awt.datatransfer.*;
    import javax.swing.*;
    public class BasicDnD {
      private JList list;
      public JList makeList() {
        DefaultListModel<String> m = new DefaultListModel<>();
        m.addElement("Martha Washington");
        m.addElement("Abigail Adams");
        m.addElement("Martha Randolph");
        list = new JList<String>(m);
        list.setTransferHandler(new TransferHandler() {
          @Override public boolean canImport(TransferHandler.TransferSupport info) {
            if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
              return false;
            }
            JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
            if (dl.getIndex() == -1) {
              return false;
            }
            return true;
          }
          @Override public int getSourceActions(JComponent c) {
            setDragImage(makeImageFromString(c));
            return COPY;
          }
          private final JPanel p = new JPanel();
          private BufferedImage br;
          private int width, height;
          private BufferedImage makeImageFromString(JComponent src) {
            JList l = (JList)src;
            int idx = l.getSelectedIndex();
            Rectangle rect = list.getCellBounds(idx,idx);
            if(rect==null) return null;
            if(br==null || rect.width!=width || rect.height!=height) {
              width  = rect.width;
              height = rect.height;
              br = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
            }
            Component c = l.getCellRenderer().getListCellRendererComponent(
                l, l.getSelectedValue(), idx, false, false);
            Graphics g = br.getGraphics();
            g.clearRect(0,0,width,height);
            SwingUtilities.paintComponent(g, c, p, 0, 0, width, height);
            g.dispose();
            return br;
          }
          @Override protected Transferable createTransferable(JComponent c) {
            JList list = (JList)c;
            Object[] values = list.getSelectedValues();
            StringBuffer buff = new StringBuffer();
            for (int i = 0; i < values.length; i++) {
              Object val = values[i];
              buff.append(val == null ? "" : val.toString());
              if (i != values.length - 1) {
                buff.append("\n");
              }
            }
            return new StringSelection(buff.toString());
          }
        });
        list.setDropMode(DropMode.ON_OR_INSERT);
        list.setDragEnabled(true);
        return list;
      }
      public JComponent makeUI() {
        JPanel panel = new JPanel(new GridLayout(2,1));
        JTextArea textArea = new JTextArea("Drag here from JList!");
        panel.add(new JScrollPane(textArea));
        panel.add(new JScrollPane(makeList()));
        return panel;
      }
      private static void createAndShowGUI() {
        JFrame f = new JFrame("BasicDnD");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new BasicDnD().makeUI());
        f.setSize(320, 320);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() { createAndShowGUI(); }
        });
      }
    }
    

答案 1 :(得分:1)

为了让TransferHandler显示自定义图像(发生拖动时),您必须创建一个TransferHandler的子类,并使用以下函数覆盖它:

  1. public int getSourceActions(JComponent) - 它必须返回源支持的操作(从中启动拖动的JComponent),如果启动时拖动请求的操作(参见5)不匹配,则它将无效。 / LI>
  2. public Transferable createTransferable(JComponent c) - TransferHandler必须返回Transferable对象,如果返回null,则不会启动拖动。
  3. public Image getDragImage()需要重新启动想要的图片,或者应该在自定义TransferHandler的实例上调用setDragImage()
  4. 要开始拖动,请使用以下方法覆盖/扩展MouseMotionListener:

    public void mouseDragged(MouseEvent e){ JComponent jc = (JComponent)e.getSource(); jc.getTransferHandler().exportAsDrag(jc, e,TransferHandler.COPY); }

    并将JComponent TransferHandler和MouseMotionListener设置为:

    myJComponent.setTransferHandler(new myCustomTransferHandler());
    myJComponent.addMouseMotionListener(new myCustomMouseMotionListener());
    

    一个完整的工作示例:

    package test;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.datatransfer.*;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseMotionListener;
    import javax.imageio.ImageIO;
    
    public class DragTest{
    Image dragImage;
    
    public static void main(String[] args){
        new DragTest();
    }
    
    public DragTest(){
        try{
            dragImage = javax.imageio.ImageIO.read( new java.net.URL(
                    "https://www.icon2s.com/wp-content/uploads/2013/07/black-white-metro-file-icon.png"));
            //dragImage = ImageIO.read(new java.io.File("icon.png")); //can be used to read image from file
        }catch(java.io.IOException e1){
            e1.printStackTrace();
            return;
        }
        dragImage = dragImage.getScaledInstance(64, 64, Image.SCALE_DEFAULT); //scaling the image
        JFrame frame = new JFrame();
        frame.setLayout(null);
        frame.setSize(500,500); frame.setLocationRelativeTo(null); //size and location
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyJComponent myJC = new MyJComponent();
        myJC.setBounds(50,50,100,100);
        myJC.addMouseMotionListener(new MouseMotionListener(){
            @Override
            public void mouseDragged(MouseEvent e){
                JComponent src = (JComponent)e.getSource();
                src.getTransferHandler().exportAsDrag(src, e, TransferHandler.COPY); //try to export with the copy action - TransferHandler should support copy 
            }
            @Override
            public void mouseMoved(MouseEvent e){}
        });
        myJC.setTransferHandler(new TransferHandler(){
            @Override public Image getDragImage(){ return(dragImage);}
            @Override public int getSourceActions(JComponent c){
                return(COPY_OR_MOVE); //supporting both copy and move
            }
            @Override public Transferable createTransferable(JComponent c){
                return(new Transferable(){
                    @Override
                    public boolean isDataFlavorSupported(DataFlavor flavor){
                        return false;
                    }
                    @Override
                    public DataFlavor[] getTransferDataFlavors(){
                        return null;
                    }
                    @Override
                    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, java.io.IOException {
                        return null;
                    }
                });
            }
        });
        frame.add(myJC);
        frame.setVisible(true);
    }
    
    private class MyJComponent extends JComponent{
        @Override
        public void paintComponent(Graphics g){
            g.setColor(Color.RED);
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }
    }