5

我正在尝试设置代码,以便用户可以从 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();
            }
        });
    }
}
4

2 回答 2

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

//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(...) 方法。

在此处输入图像描述

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(); }
    });
  }
}
于 2012-07-12T09:16:42.840 回答
1

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

  1. public int getSourceActions(JComponent)- 它必须返回源(发起拖动的JComponent)支持的动作,如果发起拖动时请求的动作(参见5)不匹配,它将不起作用。
  2. public Transferable createTransferable(JComponent c)- TransferHandler 必须返回一个Transferable 对象,如果返回null,则不会启动拖动。
  3. public Image getDragImage()需要重新调用想要的图像,或者setDragImage()应该在自定义 TransferHandler 的实例上调用

要开始拖动,请使用以下命令覆盖/扩展 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());
    }
}
}
于 2018-03-18T00:52:51.780 回答