我一直在互联网上搜索示例或如何使用 java 的拖放。我找到了一些,但所有的例子都只允许你拖到一个特定的位置,即另一个列表框或文本区域。我想知道是否有办法将项目拖到 jpanel 或类似容器上,让项目自由地放在容器上的任何位置。
3 回答
只要目标是您拖动的项目的受支持放置目标,那么您就可以将其放置到容器中,例如JPanel
.
您可以控制拖动项目在放置位置的显示方式。如果您的面板覆盖paintComponent()
,那么您可以绘制您认为合适的项目。
'是一种将项目拖入 jpanel 的方法'
您可以将 DropTarget 设置为您的 JPanel。
public class MyDropTarget extends JPanel implements DropTargetListener {
private MyImage image;
private String text;
public MyDropTarget() {
setBackground(new Color(30,60,10));
this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, new Color(30,60,10).brighter(), new Color(30,60,10).darker() ) );
DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this, true, null);
this.setDropTarget( dt );
}
@Override
public void paintComponent( Graphics g ) {
super.paintComponent( g );
if( image != null && image.getImage() != null ) {
g.drawImage( image.getImage(), 0, 0, null );
if(image.isError()){
g.setColor(Color.BLACK);
g.drawString( text, 0, 0 );
}
}
}
public void dragEnter( DropTargetDragEvent dtde ) {
this.setBorder( BorderFactory.createBevelBorder( BevelBorder.RAISED, Color.RED.brighter(), Color.RED.darker() ) );
}
public void dragExit( DropTargetEvent dte ) {
this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, UIManager.getColor( "MenuBar.highlight" ), UIManager.getColor( "MenuBar.shadow" ) ) );
}
public void dragOver( DropTargetDragEvent dtde ) {
}
public void drop( DropTargetDropEvent dtde ) {
try {
text = (String) dtde.getTransferable().getTransferData( DataFlavor.stringFlavor );
image = (MyImage)dtde.getTransferable().getTransferData( DataFlavor.imageFlavor );
this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, new Color(30,60,10).brighter(), new Color(30,60,10).darker() ) );
dtde.dropComplete( true );
repaint();
} catch( UnsupportedFlavorException e ) {
e.printStackTrace();
} catch( IOException e ) {
e.printStackTrace();
}
this.setDropTarget( null );
}
public void dropActionChanged( DropTargetDragEvent dtde ) {
}
}
我以这种方式实现了拖放:
Java 6 中已经出现了非常方便的拖放实现机制,但它确实有其缺点。例如,您应该明确指定放置目标,当您需要在放置目标附近放置对象时,这不是很有用。同样在标准实现中,不能保证侦听器方法的执行顺序。我将告诉您实现更具扩展性的拖放的概念。
最初,鼠标侦听器(Mouse Listener 和 MouseMotionListener)应分配给所有拖动源。它需要实现3个方法:鼠标点击对象的方法、按住鼠标按钮移动鼠标的方法(MouseMotionListener中的mouseDragged)和鼠标向上的方法。
侦听器分配如下所示:
component.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
//block click right mouse button
if (MouseEvent.BUTTON1 == e.getButton()) {
startDrag(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
//block click right mouse button
if (MouseEvent.BUTTON1 == e.getButton()) {
endDrag(e);
}
}
});
component.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
drag(e);
}
});
因此,当您单击对象拖放开始时,当您移动鼠标时,对象应该被移动,当您释放鼠标时,对象应该改变它的位置并被移动到一个新的容器中。如果要在一个容器的框架内移动对象,则可以只实现 mouseDragged() 方法,在该方法中,被拖动对象的坐标会发生变化:
@Override
public void mouseDragged(MouseEvent e) {
Point mouseLocation = e.getLocationOnScreen();
Component draggedComponent = (Component) e.getSource();
SwingUtilities.convertPointFromScreen(mouseLocation,
draggedComponent.getParent());
draggedComponent.setLocation(mouseLocation);
}
但是被拖动对象的坐标可以相对于它所在的容器来设置。因此,当鼠标移动到另一个容器时,需要在新的容器中添加组件,计算新的坐标等。这种方法不是很美观,扩展性也不是很好,所以我建议使用 GlassPane 来显示被拖动的对象。
该算法如下所示:
单击对象。
获取对象的屏幕截图(请参阅如何制作屏幕截图)。隐藏原始对象。
根据鼠标的坐标在 glassPane 上绘制对象的屏幕截图。
当您移动鼠标时,您需要根据新坐标重新绘制屏幕截图。
当您释放鼠标时,您需要将对象放在光标所在的容器上。
显示原始对象。
使用这种方法,我们对放置光标以进行 Drop 的容器没有任何依赖,相应地,对象可以在任何地方“Dropped”。
具有透明效果的 GlassPane:
public class GhostGlassPane extends JPanel {
private final AlphaComposite composite;
private BufferedImage ghostImage = null;
private Point location = new Point(0, 0);
public GhostGlassPane() {
setOpaque(false);
composite = AlphaComposite.getInstance(AlphaComposite.
SRC_OVER, 0.7f);
}
public void paintComponent(Graphics g) {
if (ghostImage == null)
return;
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(composite);
g2.drawImage(ghostImage, (int) (location.getX()),
(int) (location.getY()), null);
}
}
在这个回复中,只给出了实现的概念。
此信息摘自我的文章:Java 小程序开发过程中的常见问题