【发布时间】:2022-01-14 16:53:55
【问题描述】:
我正在学习 Java Swing 中的拖放功能,因此我修改了一个示例应用程序,如下所示:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import java.util.Arrays;
import javax.activation.*;
import javax.swing.*;
public class Demo_Drag_And_Drop_Panel extends JPanel
{
public Demo_Drag_And_Drop_Panel()
{
DefaultListModel<Item_Panel> m=new DefaultListModel<>();
for (String s : Arrays.asList("error","information","question","warning")) m.addElement(new Item_Panel(s));
JList<Item_Panel> list=new JList<>(m);
list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
list.setTransferHandler(new ListItem_TransferHandler());
list.setDropMode(DropMode.INSERT);
list.setDragEnabled(true);
list.setLayoutOrientation(JList.HORIZONTAL_WRAP); // http://java-swing-tips.blogspot.jp/2008/10/rubber-band-selection-drag-and-drop.html
list.setVisibleRowCount(0);
list.setFixedCellWidth(300);
list.setFixedCellHeight(36);
list.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
list.setCellRenderer(new ListCellRenderer<Item_Panel>()
{
// private final JPanel p=new JPanel(new BorderLayout());
private final JPanel p=new JPanel(new FlowLayout(0,1,1));
JLabel icon=new JLabel((Icon)null,JLabel.CENTER);
JButton button=new JButton();
JLabel label=new JLabel();
JTextField textField=new JTextField();
@Override public Component getListCellRendererComponent(JList list,Item_Panel value,int index,boolean isSelected,boolean cellHasFocus)
{
icon.setIcon(value.icon);
button.setText(value.button.getText());
button.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
if ((e.getModifiers() & InputEvent.BUTTON1_MASK)!=0)
{
// Out("mouseClicked : Left");
Out(value.name);
}
else if ((e.getModifiers() & InputEvent.BUTTON2_MASK)!=0)
{
// Out("mouseClicked : Middle");
}
else if ((e.getModifiers() & InputEvent.BUTTON3_MASK)!=0)
{
// Out("mouseClicked : Right");
}
}
});
label.setText(value.name);
label.setForeground(isSelected?list.getSelectionForeground():list.getForeground());
textField.setText(value.textField.getText());
textField.setEditable(true);
p.add(icon);
p.add(button);
p.add(label);
p.add(textField);
p.setBackground(isSelected?list.getSelectionBackground():list.getBackground());
return p;
}
});
add(new JScrollPane(list));
}
private static void out(String message) { System.out.print(message); }
private static void Out(String message) { System.out.println(message); }
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); }
public static void createAndShowGUI()
{
JFrame f=new JFrame("Demo_Drag_And_Drop_Panel");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new Demo_Drag_And_Drop_Panel());
f.setSize(350,213);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class Item_Panel
{
public final String name;
public final Icon icon;
public final JButton button;
public final JTextField textField;
public Item_Panel(String name)
{
this.name=name;
icon=UIManager.getIcon("OptionPane."+name+"Icon");
button=new JButton(name);
textField=new JTextField(name);
}
}
//@camickr already suggested above.
//http://docs.oracle.com/javase/tutorial/uiswing/dnd/dropmodedemo.html
class ListItem_TransferHandler extends TransferHandler
{
private final DataFlavor localObjectFlavor;
private Object[] transferedObjects=null;
public ListItem_TransferHandler() { localObjectFlavor=new ActivationDataFlavor(Object[].class,DataFlavor.javaJVMLocalObjectMimeType,"Array of items"); }
@SuppressWarnings("deprecation")
@Override protected Transferable createTransferable(JComponent c)
{
JList list=(JList)c;
indices=list.getSelectedIndices();
transferedObjects=list.getSelectedValues();
return new DataHandler(transferedObjects,localObjectFlavor.getMimeType());
}
@Override public boolean canImport(TransferSupport info)
{
if (!info.isDrop() || !info.isDataFlavorSupported(localObjectFlavor)) return false;
return true;
}
@Override public int getSourceActions(JComponent c)
{
return MOVE; //TransferHandler.COPY_OR_MOVE;
}
@SuppressWarnings("unchecked")
@Override public boolean importData(TransferSupport info)
{
if (!canImport(info)) return false;
JList target=(JList)info.getComponent();
JList.DropLocation dl=(JList.DropLocation)info.getDropLocation();
DefaultListModel listModel=(DefaultListModel)target.getModel();
int index=dl.getIndex();
int max=listModel.getSize();
if (index<0||index>max) index=max;
addIndex=index;
try
{
Object[] values=(Object[])info.getTransferable().getTransferData(localObjectFlavor);
addCount=values.length;
for (int i=0;i<values.length;i++)
{
int idx=index++;
listModel.add(idx,values[i]);
target.addSelectionInterval(idx,idx);
}
return true;
}
catch (UnsupportedFlavorException ufe) { ufe.printStackTrace(); }
catch (IOException ioe) { ioe.printStackTrace(); }
return false;
}
@Override protected void exportDone(JComponent c,Transferable data,int action) { cleanup(c,action==MOVE); }
private void cleanup(JComponent c,boolean remove)
{
if (remove&&indices!=null)
{
JList source=(JList)c;
DefaultListModel model=(DefaultListModel)source.getModel();
if (addCount>0)
{
//http://java-swing-tips.googlecode.com/svn/trunk/DnDReorderList/src/java/example/MainPanel.java
for (int i=0;i<indices.length;i++) if (indices[i]>=addIndex) indices[i]+=addCount;
}
for (int i=indices.length-1;i>=0;i--)
{
model.remove(indices[i]);
}
}
indices=null;
addCount=0;
addIndex=-1;
}
private int[] indices=null;
private int addIndex=-1; //Location where items were added
private int addCount=0; //Number of items added.
}
但是当我运行它时,我注意到按钮不可点击并且文本字段不可编辑,如何修复它们?换句话说,我希望能够单击按钮并输出一些信息,并能够单击文本字段并编辑其中的文本,该怎么做?
【问题讨论】:
-
“渲染”不是“实时组件”,它们是快照,直接绘制在父组件上。要回答您的问题,您不知道,
JList不支持“编辑器”,例如JTable -
我必须做些什么才能达到预期的效果[能够拖放并且仍然能够单击 JPanel 中的按钮并编辑文本字段中的文本]?我的意思是:有没有办法改变应用程序以使用其他东西代替 JList?
-
并非没有大量工作。我可能会考虑先看看
JTable -
您还应该注意传输物理组件是有问题的,相反,您应该在开始拖动(移除物理组件)时存储它的“状态”,并在放下时创建一个具有状态的新组件
标签: java swing drag-and-drop