我注意到从JList
的拖放支持中使用setDragImage
在Windows 10 Professional x86上有效,而在带有XFCE的Arch Linux 4.17.5上则无效。
可见差异:
起初,我怀疑这可能是由于JDK版本不同而引起的:Windows上的Oracle JDK和Linux上的OpenJDK(版本1.8.0_172)。
但是切换到Oracle JDK 1.8.0_172 on Arch Linux后,我得到了相同的结果。
在Linux上使用IntelliJ进行调试时,我可以看到从BufferedImage
的元素创建的拖拽图像恰好是JList
,但对setDragImage
的调用却没有似乎对Linux有任何影响。
以下重现此问题的代码是aterai's answer here的修改版本:
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.image.BufferedImage;
import java.util.List;
// From https://stackoverflow.com/questions/11437402/setdragimage-not-working-java-7#11448623
public class BasicDnd {
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) {
printJavaInfo();
EventQueue.invokeLater(BasicDnd::createAndShowGUI);
}
private static void printJavaInfo() {
Package runtimePackage = Runtime.class.getPackage();
String specVendor = runtimePackage.getSpecificationVendor();
String implementationVendor = runtimePackage.getImplementationVendor();
String version = runtimePackage.getImplementationVersion();
System.out.println("Specification vendor: " + specVendor);
System.out.println("Implementation vendor: " + implementationVendor);
System.out.println("JRE version: " + version);
}
private JList makeList() {
DefaultListModel<String> m = new DefaultListModel<>();
m.addElement("Martha Washington");
m.addElement("Abigail Adams");
m.addElement("Martha Randolph");
JList<String> list = new JList<>(m);
list.setTransferHandler(new TransferHandler() {
private final JPanel p = new JPanel();
private BufferedImage bufferedImage;
private int width, height;
@Override
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
return dl.getIndex() != -1;
}
@Override
public int getSourceActions(JComponent c) {
BufferedImage img = makeImageFromString(c);
if (img != null) {
setDragImage(img);
}
return COPY;
}
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 (bufferedImage == null || rect.width != width || rect.height != height) {
width = rect.width;
height = rect.height;
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
Component c = l.getCellRenderer().getListCellRendererComponent(
l, l.getSelectedValue(), idx, false, false);
Graphics g = bufferedImage.getGraphics();
g.clearRect(0, 0, width, height);
SwingUtilities.paintComponent(g, c, p, 0, 0, width, height);
g.dispose();
return bufferedImage;
}
@Override
protected Transferable createTransferable(JComponent c) {
JList list = (JList) c;
List values = list.getSelectedValuesList();
StringBuilder buff = new StringBuilder();
for (int i = 0; i < values.size(); i++) {
Object val = values.get(i);
buff.append(val == null ? "" : val.toString());
if (i != values.size() - 1) {
buff.append("\n");
}
}
return new StringSelection(buff.toString());
}
});
list.setDropMode(DropMode.ON_OR_INSERT);
list.setDragEnabled(true);
return list;
}
private 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;
}
}
如何在Linux上获取拖动图像?