問題描述
我遇到了一個關于使用拖放對 JList 中的元素進行重新排序的問題.以下代碼是對代碼的修改,您可以在其中將元素從一個 JList 拖到另一個(僅以一種方式工作).我試圖讓它只對一個 JList 可用,但元素甚至不能被拖出列表.所以我想它不能這樣做.任何想法我做錯了什么或沒有考慮到?
I encountered a problem regarding reordering elements in a JList using Drag and Drop. This following code is a modification of a code where you could drag elements from one JList to another (worked only one way). I tried to make it usable for only one JList, but the elements can't even be dragged out of the list. So I guess it can't be done this way. Any ideas what I'm doing wrong or not taking into consideration?
這個想法是讓它為帶有縮略圖的 Jlist 工作,但因為我什至不能讓它只用字符串工作......我一直在研究幾個 D'n'D 教程,但我仍然無法讓它工作.任何幫助表示贊賞.
The idea is to get it to work for a Jlist with thumbnails, but since I can't even get it to work with just strings... I have been looking into several D'n'D tutorials, but still I can't get it to work. Any help is appreciated.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.io.IOException;
public class DragAndDrop extends JFrame {
DefaultListModel<String> transport = new DefaultListModel<String>();
JList<String> transportList = new JList<String>(transport);
public DragAndDrop() {
setLayout(new FlowLayout());
transport.addElement("Bike");
transport.addElement("Car");
transport.addElement("Truck");
transport.addElement("Boat");
JScrollPane transportScroll = new JScrollPane(transportList);
transportScroll.setBorder(new TitledBorder("Transportation"));
add(transportScroll);
transportList.setDragEnabled(true);
transportList.setTransferHandler(new TransferHandler() {
int index;
@Override
public int getSourceActions(JComponent comp) {
return COPY_OR_MOVE;
}
@Override
public Transferable createTransferable(JComponent comp) {
index = transportList.getSelectedIndex();
return new StringSelection(transportList.getSelectedValue());
}
@Override
public void exportDone( JComponent comp, Transferable trans, int action ) {
if (action==MOVE) {
transport.remove(index);
}
}
});
transportList.setDropMode(DropMode.ON);
transportList.setTransferHandler(new TransferHandler() {
@Override
public boolean canImport(TransferHandler.TransferSupport support) {
// data of type string?
return support.isDataFlavorSupported(DataFlavor.stringFlavor);
}
@Override
public boolean importData(TransferHandler.TransferSupport support) {
try {
// convert data to string
String s = (String)support.getTransferable().getTransferData(DataFlavor.stringFlavor);
JList.DropLocation dl = (JList.DropLocation)support.getDropLocation();
transport.add(dl.getIndex(),s);
return true;
}
catch (UnsupportedFlavorException e) {}
catch (IOException e) {}
return false;
}
});
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new DragAndDrop();
}
}
PS.抱歉,如果這是一個重新發布.
PS. Sorry if this turns out to be a re-post.
編輯我想我已經解決了:必須使用不同的 transferHandlers - 應該只有一個包含第二個中的所有方法.
EDIT I think I got it fixed: had to different transferHandlers - should only have one with all the methods from the second one as well.
推薦答案
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DragSource;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
// import javax.activation.ActivationDataFlavor;
// import javax.activation.DataHandler;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
public class DragAndDropTest {
public JComponent makeUI() {
DefaultListModel<Thumbnail> m = new DefaultListModel<>();
for (String s : Arrays.asList("error", "information", "question", "warning")) {
m.addElement(new Thumbnail(s));
}
JList<Thumbnail> list = new JList<>(m);
list.getSelectionModel().setSelectionMode(
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
list.setTransferHandler(new ListItemTransferHandler());
list.setDropMode(DropMode.INSERT);
list.setDragEnabled(true);
// https://java-swing-tips.blogspot.com/2008/10/rubber-band-selection-drag-and-drop.html
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(0);
list.setFixedCellWidth(80);
list.setFixedCellHeight(80);
list.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
list.setCellRenderer(new ListCellRenderer<Thumbnail>() {
private final JPanel p = new JPanel(new BorderLayout());
private final JLabel icon = new JLabel((Icon)null, JLabel.CENTER);
private final JLabel label = new JLabel("", JLabel.CENTER);
@Override
public Component getListCellRendererComponent(
JList<? extends Thumbnail> list, Thumbnail value, int index,
boolean isSelected, boolean cellHasFocus) {
icon.setIcon(value.icon);
label.setText(value.name);
label.setForeground(isSelected ? list.getSelectionForeground()
: list.getForeground());
p.add(icon);
p.add(label, BorderLayout.SOUTH);
p.setBackground(isSelected ? list.getSelectionBackground()
: list.getBackground());
return p;
}
});
return new JScrollPane(list);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> createAndShowGUI());
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new DragAndDropTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class Thumbnail implements Serializable {
public final String name;
public final Icon icon;
public Thumbnail(String name) {
this.name = name;
this.icon = UIManager.getIcon("OptionPane." + name + "Icon");
}
}
// @camickr already suggested above.
// https://docs.oracle.com/javase/tutorial/uiswing/dnd/dropmodedemo.html
@SuppressWarnings("serial")
class ListItemTransferHandler extends TransferHandler {
protected final DataFlavor localObjectFlavor;
protected int[] indices;
protected int addIndex = -1; // Location where items were added
protected int addCount; // Number of items added.
public ListItemTransferHandler() {
super();
// localObjectFlavor = new ActivationDataFlavor(
// Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items");
localObjectFlavor = new DataFlavor(Object[].class, "Array of items");
}
@Override
protected Transferable createTransferable(JComponent c) {
JList<?> source = (JList<?>) c;
c.getRootPane().getGlassPane().setVisible(true);
indices = source.getSelectedIndices();
Object[] transferedObjects = source.getSelectedValuesList().toArray(new Object[0]);
// return new DataHandler(transferedObjects, localObjectFlavor.getMimeType());
return new Transferable() {
@Override public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {localObjectFlavor};
}
@Override public boolean isDataFlavorSupported(DataFlavor flavor) {
return Objects.equals(localObjectFlavor, flavor);
}
@Override public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (isDataFlavorSupported(flavor)) {
return transferedObjects;
} else {
throw new UnsupportedFlavorException(flavor);
}
}
};
}
@Override
public boolean canImport(TransferSupport info) {
return info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
}
@Override
public int getSourceActions(JComponent c) {
Component glassPane = c.getRootPane().getGlassPane();
glassPane.setCursor(DragSource.DefaultMoveDrop);
return MOVE; // COPY_OR_MOVE;
}
@SuppressWarnings("unchecked")
@Override
public boolean importData(TransferSupport info) {
TransferHandler.DropLocation tdl = info.getDropLocation();
if (!canImport(info) || !(tdl instanceof JList.DropLocation)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) tdl;
JList target = (JList) info.getComponent();
DefaultListModel listModel = (DefaultListModel) target.getModel();
int max = listModel.getSize();
int index = dl.getIndex();
index = index < 0 ? max : index; // If it is out of range, it is appended to the end
index = Math.min(index, max);
addIndex = index;
try {
Object[] values = (Object[]) info.getTransferable().getTransferData(localObjectFlavor);
for (int i = 0; i < values.length; i++) {
int idx = index++;
listModel.add(idx, values[i]);
target.addSelectionInterval(idx, idx);
}
addCount = values.length;
return true;
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
return false;
}
@Override
protected void exportDone(JComponent c, Transferable data, int action) {
c.getRootPane().getGlassPane().setVisible(false);
cleanup(c, action == MOVE);
}
private void cleanup(JComponent c, boolean remove) {
if (remove && Objects.nonNull(indices)) {
if (addCount > 0) {
// https://github.com/aterai/java-swing-tips/blob/master/DragSelectDropReordering/src/java/example/MainPanel.java
for (int i = 0; i < indices.length; i++) {
if (indices[i] >= addIndex) {
indices[i] += addCount;
}
}
}
JList source = (JList) c;
DefaultListModel model = (DefaultListModel) source.getModel();
for (int i = indices.length - 1; i >= 0; i--) {
model.remove(indices[i]);
}
}
indices = null;
addCount = 0;
addIndex = -1;
}
}
這篇關于使用拖放重新排序 JList的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!