在Swing中实时拖放 [英] Realtime drag and drop in Swing

查看:117
本文介绍了在Swing中实时拖放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用拖放来摆放四个组件之一的按钮。为了使它更有吸引力,而不仅仅是鼠标指示被拖动的东西(这是正常工作),我想要实时显示。除了鼠标返回拖动的组件之外,这个工作除外:drag listener注册了一个dragExit事件,该事件删除了一个按钮,这个按钮使监听器能够集中在父组件上并触发dragEnter导致闪烁。我需要使按钮不会影响拖动监听器。任何想法?





这是我添加的jlabel(我知道jlabel不是一个好的选择,但它的工作很好,很容易可以显示一个图像,我需要)

  import java.awt.Point; 
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd。*;
import java.io.IOException;
import javax.swing。*;


//这里是拖动的按钮
public class DndLabel extends JLabel implements DropTargetListener {

private DropTarget target;
私人DndButton按钮;
public DndLabel last;

//用数据初始化JTable
public DndLabel(){
super();

//标记一个DropTarget
target = new DropTarget(this,this);

//使用自定义传输处理程序
setTransferHandler(new MyTransferHandler());
}

public void dragEnter(DropTargetDragEvent dtde){
System.out.println(enter);

尝试{
//获取发生下降点的位置
Point loc = dtde.getLocation();

//获取传输数据
可传输t = dtde.getTransferable();

//使用Transferable
获取数据风格DataFlavor [] d = t.getTransferDataFlavors();

button =(DndButton)t.getTransferData(d [0]);

button.setBounds(loc.x,0,100,50);

add(button);

//如果DataFlavors匹配DnDTable
//(即,我们不希望ImageFlavor标记图像传输)
if(getTransferHandler()。 canImport(this,d)){

//然后导入Draggable JComponent并重新绘制()JTable
((MyTransferHandler)getTransferHandler())。importData(this,(DndButton)t .getTransferData(d [0]),loc);
repaint();
} else {
return;
}
} catch(UnsupportedFlavorException ex){
ex.printStackTrace();
} catch(IOException ex){
ex.printStackTrace();
}
}

@Override
public void dragOver(DropTargetDragEvent dtde){
button.setLocation(dtde.getLocation()。x,0) ;
}

public void dragExit(DropTargetEvent dte){
System.out.println(remove);

last = null;
删除(按钮);
repaint();

}

//发生Drop发生时会发生
public void drop(DropTargetDropEvent dtde){
System.out.println(下降!);
尝试{
//获取发生下降点的位置
Point loc = dtde.getLocation();

//获取传输数据
可传输t = dtde.getTransferable();

//使用Transferable
获取数据风格DataFlavor [] d = t.getTransferDataFlavors();

DndButton tempButton =(DndButton)t.getTransferData(d [0]);

tempButton.setBounds(loc.x,0,100,50);

add(tempButton);

//如果DataFlavors匹配DnDTable
//(即,我们不希望ImageFlavor标记图像传输)
if(getTransferHandler()。 canImport(this,d)){

//然后导入Draggable JComponent并重新绘制()JTable
((MyTransferHandler)getTransferHandler())。importData(this,(DndButton)t .getTransferData(d [0]),loc);
repaint();
} else {
return;
}

} catch(UnsupportedFlavorException ex){
ex.printStackTrace();
} catch(IOException ex){

} finally {
dtde.dropComplete(true);
}
}

@Override
public void dropActionChanged(DropTargetDragEvent dtde){
}

class MyTransferHandler extends TransferHandler {

//测试一个有效的JButton DataFlavor
public boolean canImport(JComponent c,DataFlavor [] f){
DataFlavor temp = new DataFlavor(DndButton.class,JButton ); $ data $ d $ f $ {
if(d.equals(temp)){
return true;
}

}
return false;
}

//将数据添加到JTable
public boolean importData(JComponent comp,Transferable t,Point p){
try {
DndButton tempButton =(DndButton)t.getTransferData(new DataFlavor(DndButton.class,JButton));

} catch(UnsupportedFlavorException | IOException ex){
System.err.println(ex);
}
返回true;
}
}
}
类DndButton扩展JButton实现Transferable,DragSourceListener,DragGestureListener {

//将此JButton标记为Drag $的源代码b $ b私有DragSource源码;
私人TransferHandler t;

public DndButton(){
this();
}

public DndButton(String message){
super(message);

// TransferHandler返回一个新的DnDButton
//要转移到拖动
t = new TransferHandler(){

public Transferable createTransferable JComponent c){
return new DndButton(getText());
}
};
setTransferHandler(t);

//拖动将复制DnDButton而不是移动它
source = new DragSource();
source.createDefaultDragGestureRecognizer(this,DnDConstants.ACTION_MOVE,this);
}

// DataFlavor是一个标记,让DropTarget知道如何
//处理可传递
public DataFlavor [] getTransferDataFlavors(){
return new DataFlavor [] {new DataFlavor(DndButton.class,JButton)};
}

public boolean isDataFlavorSupported(DataFlavor flavor){
return true;
}

public Object getTransferData(DataFlavor flavor){
return this;
}

public void dragEnter(DragSourceDragEvent dsde){
}

public void dragOver(DragSourceDragEvent dsde){
// this。 setLocation(dsde.getX() - 150,0);
}

public void dropActionchanged(DragSourceDragEvent dsde){
}

public void dragExit(DragSourceEvent dse){
}

//当拖动完成时,然后重新绘制DnDButton
//,所以它看起来不像现在还被按下
public void dragDropEnd(DragSourceDropEvent dsde){
// JComponent c =(JComponent)this.getParent();
//c.remove(this);
//c.repaint();
}

//当识别出DragGesture时,启动Drag
public void dragGestureRecognized(DragGestureEvent dge){
source.startDrag(dge,DragSource.DefaultMoveDrop, DndButton.this,this);
}

@Override
public void dropActionChanged(DragSourceDragEvent dsde){
}
}

class Main {

public static void main(String [] args){
JFrame f = new JFrame(sscce);
f.setBounds(0,0,500,80);
f.setVisible(true);
DndLabel trackOne = new DndLabel();
trackOne.setBounds(0,0,500,50);
f.add(trackOne);
DndButton b = new DndButton(hello);
b.setBounds(0,0,100,trackOne.getHeight());

trackOne.add(b);
trackOne.revalidate();
trackOne.repaint();
}
}


解决方案

个人来说,可能会拒绝这样做。问题是,每次添加组件时,组件会干扰层次结构中的鼠标监听器,导致容器被通知退出事件,这导致按钮被删除,容器被通知进入事件而且这个周期还在继续。



个人来说,我会做两件事之一。




  • 在玻璃窗格中绘制按钮或
  • 的描述
  • 绘制表示的拖动面板上的按钮



这样可以消除按钮导致干扰所涉及的鼠标听众的可能性。



查看我的拖动图像比你的更好。当你在那里挖掘一下,蒂姆做了一些关于drag'n'drop的优秀文章,值得一读。


I am using drag and drop in swing to place a button on one of four components. To make it more appealing instead of just the mouse indicating something being dragged (which is working fine) I wanted to show it in real time. This works except if the mouse goes back over the component being dragged the drag listener registers a dragExit event which removes the button which causes the listener to focus back on the parent component and fire a dragEnter causing a flicker. I need to make the button not affect the drag listener somehow. Any ideas?

this is the jlabel I'm adding it too (I know jlabel is not a good choice but it is working well and easily can display an image which I need)

import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.io.IOException;
import javax.swing.*;


//and here is the button to drag   
public class DndLabel extends JLabel implements DropTargetListener {

    private DropTarget target;
    private DndButton button;
    public DndLabel last;

    //initialize the JTable with the data
    public DndLabel() {
        super();

        //mark this a DropTarget
        target = new DropTarget(this, this);

        //have it utilize a custom transfer handler
        setTransferHandler(new MyTransferHandler());
    }

    public void dragEnter(DropTargetDragEvent dtde) {
        System.out.println("enter");

        try {
            //get the Point where the drop occurred
            Point loc = dtde.getLocation();

            //get Transfer data
            Transferable t = dtde.getTransferable();

            //get the Data flavors transferred with the Transferable
            DataFlavor[] d = t.getTransferDataFlavors();

            button = (DndButton) t.getTransferData(d[0]);

            button.setBounds(loc.x, 0, 100, 50);

            add(button);

            //and if the DataFlavors match for the DnDTable 
            //(ie., we don't want an ImageFlavor marking an image transfer)
            if (getTransferHandler().canImport(this, d)) {

                //then import the Draggable JComponent and repaint() the JTable
                ((MyTransferHandler) getTransferHandler()).importData(this, (DndButton) t.getTransferData(d[0]), loc);
                repaint();
            } else {
                return;
            }
        } catch (UnsupportedFlavorException  ex) {
            ex.printStackTrace();
        } catch(IOException ex){
            ex.printStackTrace();
        }
    }

    @Override
    public void dragOver(DropTargetDragEvent dtde) {
        button.setLocation(dtde.getLocation().x, 0);
    }

    public void dragExit(DropTargetEvent dte) {
        System.out.println("remove");

        last = null;
        remove(button);
        repaint();

    }

    //This is what happens when a Drop occurs
    public void drop(DropTargetDropEvent dtde) {
        System.out.println("drop!");
        try {
            //get the Point where the drop occurred
            Point loc = dtde.getLocation();

            //get Transfer data
            Transferable t = dtde.getTransferable();

            //get the Data flavors transferred with the Transferable
            DataFlavor[] d = t.getTransferDataFlavors();

            DndButton tempButton = (DndButton) t.getTransferData(d[0]);

            tempButton.setBounds(loc.x, 0, 100, 50);

            add(tempButton);

            //and if the DataFlavors match for the DnDTable 
            //(ie., we don't want an ImageFlavor marking an image transfer)
            if (getTransferHandler().canImport(this, d)) {

                //then import the Draggable JComponent and repaint() the JTable
                ((MyTransferHandler) getTransferHandler()).importData(this, (DndButton) t.getTransferData(d[0]), loc);
                repaint();
            } else {
                return;
            }

        } catch (UnsupportedFlavorException ex) {
            ex.printStackTrace();
        }catch(IOException ex){

        }finally {
            dtde.dropComplete(true);
        }
    }

    @Override
    public void dropActionChanged(DropTargetDragEvent dtde) {
    }

    class MyTransferHandler extends TransferHandler {

        //tests for a valid JButton DataFlavor
        public boolean canImport(JComponent c, DataFlavor[] f) {
            DataFlavor temp = new DataFlavor(DndButton.class, "JButton");
            for (DataFlavor d : f) {
                if (d.equals(temp)) {
                    return true;
                }

            }
            return false;
        }

        //add the data into the JTable
        public boolean importData(JComponent comp, Transferable t, Point p) {
            try {
                DndButton tempButton = (DndButton) t.getTransferData(new DataFlavor(DndButton.class, "JButton"));

            } catch (UnsupportedFlavorException | IOException ex) {
                System.err.println(ex);
            }
            return true;
        }
    }
}
class DndButton extends JButton implements Transferable, DragSourceListener, DragGestureListener {

    //marks this JButton as the source of the Drag
    private DragSource source;
    private TransferHandler t;

    public DndButton() {
        this("");
    }

    public DndButton(String message) {
        super(message);

        //The TransferHandler returns a new DnDButton
        //to be transferred in the Drag
        t = new TransferHandler() {

            public Transferable createTransferable(JComponent c) {
                return new DndButton(getText());
            }
        };
        setTransferHandler(t);

        //The Drag will copy the DnDButton rather than moving it
        source = new DragSource();
        source.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
    }

    //The DataFlavor is a marker to let the DropTarget know how to
    //handle the Transferable
    public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[]{new DataFlavor(DndButton.class, "JButton")};
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return true;
    }

    public Object getTransferData(DataFlavor flavor) {
        return this;
    }

    public void dragEnter(DragSourceDragEvent dsde) {
    }

    public void dragOver(DragSourceDragEvent dsde) {
        //this.setLocation(dsde.getX()-150,0);
    }

    public void dropActionchanged(DragSourceDragEvent dsde) {
    }

    public void dragExit(DragSourceEvent dse) {
    }

    //when the drag finishes, then repaint the DnDButton
    //so it doesn't look like it has still been pressed down
    public void dragDropEnd(DragSourceDropEvent dsde) {
        // JComponent c = (JComponent) this.getParent();
        //c.remove(this);
        //c.repaint();
    }

    //when a DragGesture is recognized, initiate the Drag
    public void dragGestureRecognized(DragGestureEvent dge) {
        source.startDrag(dge, DragSource.DefaultMoveDrop, DndButton.this, this);
    }

    @Override
    public void dropActionChanged(DragSourceDragEvent dsde) {
    }
}

class Main {

    public static void main(String[] args) {
        JFrame f = new JFrame("sscce");
        f.setBounds(0, 0, 500, 80);
        f.setVisible(true);
        DndLabel trackOne = new DndLabel();
        trackOne.setBounds(0, 0, 500, 50);
        f.add(trackOne);
        DndButton b = new DndButton("hello");
        b.setBounds(0, 0, 100, trackOne.getHeight());

        trackOne.add(b);
        trackOne.revalidate();
        trackOne.repaint();
    }
}

解决方案

I, personally, would probably resist doing it this way. The problem is, each time you add the component, the component is interfering with the mouse listeners in the hierarchy, causing the container to be notified of an exit event, which causes the button to be removed and the container to be notified of enter event and the cycle continues.

Personally, I would do one of two things. I would either

  • Paint to the glass pane a representation of the button or
  • Paint a representation of the button on the drag panel

This removes the possibility of the button causing interference with the mouse listeners involved.

Check out My Drag Image is Better than Yours. While you're there dig around a bit, Tim does a number of excellent articles on drag'n'drop which are worth the read

这篇关于在Swing中实时拖放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆