setDragImage无法正常工作 – Java 7

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

  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 m = new DefaultListModel<>(); m.addElement("Martha Washington"); m.addElement("Abigail Adams"); m.addElement("Martha Randolph"); list = new JList(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(); } }); } } 

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

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

要开始拖动,请使用以下内容覆盖/扩展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()); } } }