【发布时间】:2014-09-02 22:37:19
【问题描述】:
我想为组件(例如 JPanel 或 JLabel)实现自定义放置位置渲染。我的目标是当用户悬停带有可放置项目的组件时显示蓝色边框,并在离开组件时再次移除边框。
摇摆教程提供了这个:
Drop Location Rendering
这对我一点帮助都没有。我错过了enterComponent(Event e) 和exitComponent(Event e) 之类的内容,或者此页面所指的内容与我预期的不同?
所以我搜索了万维网并找到了一些示例(主要来自this blog)。过了一会儿,我可以完成我需要的工作示例(来源如下)。但是我发现所有示例都使用了 java.awt 中的类来呈现放置位置。因为我还没有完全了解所有这些拖放类,所以我没有找到一种方法来仅使用 swing 类来实现自定义放置位置渲染。
所以我的问题是:
是否可以仅使用 swing 类在 "enterComponent" 和 "exitComponent" 事件上呈现 JComponent?
补充问题:
如果我删除new DropTarget(label, dropListener); 行,ListItemTransfereHandler.importData(...) 将被调用,否则不会被调用。这是什么原因?我真的很感激一些关于 dnd 课程的课程和/或行动图表(这不是答案所必需的)。
(请不要回答 JavaFX)
工作示例的源代码(带有 AWT 类)。很抱歉代码行太多,但是 java dnd 需要很大的空间。
public class DnDTransferableTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new DnDTransferableTest();
}
});
}
public DnDTransferableTest() {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
// JPanel panel = new JPanel(new MigLayout("wrap 2, fill", "fill, grow", "align center"));
JPanel panel = new JPanel(new GridLayout(1,2));
JList<ListItem> list = new JList<ListItem>();
JLabel label = new JLabel();
// Initializing list
list.setDragEnabled(true);
list.setTransferHandler(new ListTransferHandler());
DefaultListModel<ListItem> model = new DefaultListModel<ListItem>();
for (int index = 0; index < 10; index++) {
model.addElement(new ListItem("Item", index));
}
list.setModel(model);
// Initializing label and its drop listener
label.setText("Drag on me...");
label.setTransferHandler(new ListTransferHandler());
DropTargetListener dropListener = new JLabelDropTargetListener();
new DropTarget(label, dropListener);
// Adding the components to the panel
panel.add(new JScrollPane(list), "sg test");
panel.add(label, "sg test");
frame.setContentPane(panel);
frame.setVisible(true);
}
}
class ListItem implements Transferable {
public static final DataFlavor LIST_ITEM_DATA_FLAVOR = new DataFlavor(ListItem.class, ListItem.class.getName());
private String text;
private int number;
public ListItem(String text, int number) {
this.text = text;
this.number = number;
}
public String getText() {
return text;
}
public int getNumber() {
return this.number;
}
@Override
public String toString() {
return this.getText() + ": " + this.getNumber();
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { LIST_ITEM_DATA_FLAVOR };
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(LIST_ITEM_DATA_FLAVOR);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return this;
}
}
class ListTransferHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
@Override
public boolean canImport(TransferSupport support) {
return (support.getComponent() instanceof JLabel) && support.isDataFlavorSupported(ListItem.LIST_ITEM_DATA_FLAVOR);
}
@Override
public boolean importData(TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Object value = t.getTransferData(ListItem.LIST_ITEM_DATA_FLAVOR);
if (value instanceof ListItem) {
Component component = support.getComponent();
if (component instanceof JLabel) {
((JLabel) component).setText(((ListItem) value).getNumber() + ". " + ((ListItem) value).getText());
}
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
System.out.println("import data " + accept);
return accept;
}
@Override
public int getSourceActions(JComponent c) {
return COPY;
}
@Override
protected Transferable createTransferable(JComponent c) {
if (c instanceof JList<?>) {
JList<?> list = (JList<?>) c;
Object value = list.getSelectedValue();
if (value instanceof ListItem) {
return (ListItem) value;
}
}
return null;
}
@Override
protected void exportDone(JComponent source, Transferable data, int action) {
System.out.println("ExportDone");
// Here you need to decide how to handle the completion of the
// transfer,
// should you remove the item from the list or not...
}
}
class JLabelDropTargetListener implements DropTargetListener {
private int thickness = 2;
private Border blueBorder = BorderFactory.createLineBorder(Color.BLUE, thickness);
private Border emptyBorder = BorderFactory.createEmptyBorder(thickness, thickness, thickness, thickness);
@Override
public void dragEnter(DropTargetDragEvent dtde) {
System.out.println("dragEnter");
Object src = dtde.getDropTargetContext().getComponent();
if (src instanceof JLabel) {
JLabel label = (JLabel) src;
label.setForeground(Color.RED);
label.setBorder(blueBorder);
} else {
System.out.println(src.getClass().getName());
System.out.println(dtde.getDropTargetContext().getComponent());
}
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
@Override
public void dragExit(DropTargetEvent dte) {
System.out.println("dragExit");
Component src = dte.getDropTargetContext().getComponent();
if (src instanceof JLabel) {
JLabel label = (JLabel) src;
label.setForeground(null);
label.setBorder(emptyBorder);
}
}
@Override
public void drop(DropTargetDropEvent dtde) {
System.out.println("drop");
Component src = dtde.getDropTargetContext().getComponent();
if (src instanceof JLabel) {
JLabel label = (JLabel) src;
label.setForeground(null);
label.setBorder(emptyBorder);
Transferable t = dtde.getTransferable();
Object value;
try {
value = t.getTransferData(ListItem.LIST_ITEM_DATA_FLAVOR);
if (value instanceof ListItem) {
ListItem li = (ListItem) value;
label.setText(li.getNumber() + ". " + li.getText());
}
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
【问题讨论】:
标签: java swing drag-and-drop rendering