java里的dnd

dnd是drag and drop的缩写.
java中的dnd主要涉及到3个类:TransferHandler(用来处理数据的拖放过程),Transferable(用来包装拖放的数据),和DataFlavor(用来表示拖放的数据的类型).下面来介绍这3个类的方法

1.javax.swing.TransferHandler
它有两个构造函数:
TransferHandler() 子类的便捷构造方法。


TransferHandler(String property) 构造一个通过剪贴板或拖放操作可以将 Java Bean 属性从一个组件传输到另一个组件的传输处理程序。
如,JLabel和JTextField都有text这个属性,所以可以很简单地实现从JTextField里拖文本到JLabel里,改变它的文本.下面是一个例子
在textField里输入文本后,往label里拖,label的文本就变为textField里的文本了.如果要实现从label往textField里拖,还要另外的方法,先不说

import  java.awt. * ;
import  javax.swing. * ;
import  java.awt.event. * ;
import  javax.swing.event. * ;

class  LabelDnd 
{
 JFrame mainFrame;
 JPanel mainPanel;
 JLabel label;
 JTextField textField;
 
public  LabelDnd() {
  mainFrame 
=   new  JFrame (  );
  mainPanel 
=   new  JPanel (  new  BorderLayout() );
  label 
=   new  JLabel ( " label " );
  
// 这里调用了TransferHandler的第二个构造函数,参数是一个Java Bean 属性
  label.setTransferHandler(  new  TransferHandler( " text " ) );
  textField 
=   new  JTextField( 20 );
  
// 打开textField自带的拖放功能
  textField.setDragEnabled(  true  );
  mainPanel.add( label,BorderLayout.PAGE_START );
  mainPanel.add( textField,BorderLayout.PAGE_END  );
  mainFrame.getContentPane().add( mainPanel );
  mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  mainFrame.pack();
  mainFrame.setLocationRelativeTo(
null );
  mainFrame.setVisible( 
true  );
 }
 
public   static   void  main(String[] args) 
 {
  
new  LabelDnd();
 }
}

再看一个例子,JLabel还有foreground这个属性.所以也可以很容易实现拖放改变它的前景色.在colorChooser里选一种颜色以后,在样本面板里往label一拖,label的文字的颜色就变了

import  java.awt. * ;
import  javax.swing. * ;
import  java.awt.event. * ;
import  javax.swing.event. * ;

class  LabelDnd2 
{
 JFrame mainFrame;
 JPanel mainPanel;
 JLabel label;
 JColorChooser colorChooser;
 
public  LabelDnd2() {
  mainFrame 
=   new  JFrame (  );
  mainPanel 
=   new  JPanel ();
  colorChooser 
=   new  JColorChooser ();
  colorChooser.setDragEnabled( 
true  );
  label 
=   new  JLabel ( "  i can accept color  " );
  label.setTransferHandler( 
new  TransferHandler( " foreground " ) );
  mainPanel.add( colorChooser );
  mainPanel.add( label );
  mainFrame.getContentPane().add( mainPanel );
  mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  mainFrame.pack();
  mainFrame.setLocationRelativeTo(
null );
  mainFrame.setVisible( 
true  );
 }
 
public   static   void  main(String[] args) 
 {
  
new  LabelDnd2();
 }
}

下面来看一些它的用于拖放的方法(还有一些方法一般用于绑定键盘输入,暂且不谈)
int getSourceActions(JComponent c) 返回拖放源支持的传输操作的类型。有COPY,COPY_AND_MOVE,MOVE,NONE,分别指复制,复制和移动,移动和无传输操作;参数c是拖放源


Transferable createTransferable(JComponent c)  将你要在拖放中传输的数据包装入一个Tranferable类或它的子类里面.参数c是拖放源,里面包含了你要包装的数据,例如在一个JTextField里面的文本


boolean canImport(JComponent c, DataFlavor[] transferFlavors)  判断一个拖放动作里面的数据是否可被导入到c里面,参数c是拖放目标,另外一个参数是上一个方法createTransferable封装的Transferable包含的数据的数据类型.例如拖放动作里面的数据可能既有文本又有图片,transferFlavors就会包含有这两种数据类型.但是一个JTextField是不能接受图片数据的,所以要用这个方法来判断能不能在c上导入createTransferable产生的数据


boolean importData(JComponent comp, Transferable t)  在判断完可以导入数据以后,就调用这个方法在comp上导入t里面包含的数据


void exportDone(JComponent source, Transferable data, int action)  如果你执行的是移动操作而不是拖复制,在导入完数据以后,要在拖放源上删除移动的数据,这样方法就是用来实现这个目的的.所以,这个方法不一定要重载.


void exportAsDrag(JComponent comp, InputEvent e, int action) 导致 Swing 拖动支持的启用。 comp是拖放源,包含要传输的数据,e一般是鼠标的拖事件,action就是前面提到的COPY,COPY_AND_MOVE,MOVE,NONE.

举例说明这个方法的用法.稍修改前面第一个例子就可以实现从label里往textField里拖文本

import  java.awt. * ;
import  javax.swing. * ;
import  java.awt.event. * ;
import  javax.swing.event. * ;

class  LabelDnd 
{
 JFrame mainFrame;
 JPanel mainPanel;
 JLabel label;
 JTextField textField;
 
public  LabelDnd() {
  mainFrame 
=   new  JFrame (  );
  mainPanel 
=   new  JPanel (  new  BorderLayout() );
  label 
=   new  JLabel ( " label " );
  label.setTransferHandler( 
new  TransferHandler( " text " ) );
  label.addMouseListener( 
new  MouseAdapter(){
   
public   void  mousePressed( MouseEvent e ){
    JComponent c 
=  (JComponent)e.getSource();
    TransferHandler handler 
=  c.getTransferHandler();
    handler.exportAsDrag(c,e,TransferHandler.COPY);
// 调用了exportAsDrag
   }
  } );
  textField 
=   new  JTextField( 20 );
  textField.setDragEnabled( 
true  );
  mainPanel.add( label,BorderLayout.PAGE_START );
  mainPanel.add( textField,BorderLayout.PAGE_END  );
  mainFrame.getContentPane().add( mainPanel );
  mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  mainFrame.pack();
  mainFrame.setLocationRelativeTo(
null );
  mainFrame.setVisible( 
true  );
 }
 
public   static   void  main(String[] args) 
 {
  
new  LabelDnd();
 }
}

2.java.awt.datatransfer.Transferable
这个接口用作包装要传输的数据.包装的数据一般作为实现它的类的属性


Object getTransferData(DataFlavor flavor)  返回一个对象,该对象表示将要被传输的数据.参数表示要返回的数据类型.例如,前面提到,你在一个组件上拖动,产生的Transferable可能既有文字又有图片,那么就可以用这个方法只提取其中的文字或图片.这个方法一般会在TransferHandler的importData方法里被调用.


DataFlavor[] getTransferDataFlavors()  返回一个类型数组.程序怎么知道你的Transferable包含哪些数据类型呢?通过调用这个函数就可以知道你的Transferable包含什么了.这个方法的返回值一般会作为参数传入TransferHandler 的canImport方法里


boolean isDataFlavorSupported(DataFlavor flavor) 判断你的Transferable是否包含有flavor指定的数据


3.java.awt.datatransfer.DataFlavor
这个类用来表示数据类型.方法比较多.但是,一般简单应用只要用到它的构造函数
DataFlavor() 和 DataFlavor(Class<?> representationClass, String humanPresentableName)
当你要传输自己定义的类时,这个类非常有用.


下面用例子说明以上类和接口的用法.

import  java.awt. * ;
import  javax.swing. * ;
import  java.awt.event. * ;
import  javax.swing.event. * ;
import  java.awt.datatransfer. * ;
import  java.io. * ;
class   PictureDnd
{
 JFrame mainFrame;
 JPanel mainPanel;
 PictureComponent[] pictures;
 
public  PictureDnd() {
  mainFrame 
=   new  JFrame (  );
  mainPanel 
=   new  JPanel (  new  GridLayout( 2 , 2 ) );
  
// PictureComponent是一个自定义的类
  pictures  =   new  PictureComponent[ 4 ]; 
  pictures[
0 =   new  PictureComponent(  new  ImageIcon( " images/Adele.jpg " ).getImage() );
  pictures[
1 =   new  PictureComponent(  new  ImageIcon( " images/Anya.jpg " ).getImage() );
  pictures[
2 =   new  PictureComponent(  null  );
  pictures[
3 =   new  PictureComponent(  null  );
  mainPanel.add( pictures[
0 ] );
  mainPanel.add( pictures[
1 ] );
  mainPanel.add( pictures[
2 ] );
  mainPanel.add( pictures[
3 ] );
  mainPanel.setBorder(BorderFactory.createEmptyBorder(
20 , 20 , 20 , 20 ));
  mainFrame.getContentPane().add( mainPanel );
  mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  mainFrame.setSize(
350 , 400 );
  mainFrame.setLocationRelativeTo(
null );
  mainFrame.setVisible( 
true  );
 }
 
private   class  PictureComponent  extends  JComponent 
  
implements  FocusListener,MouseListener,MouseMotionListener{
  Image image;
  
public  PictureComponent( Image image ){
   
this .image  =  image;
   setPreferredSize( 
new  Dimension( 125 , 125 ) );
   setFocusable( 
true  );
   setTransferHandler( 
new  PictureTransferHandler() );
   addFocusListener(
this );
   addMouseListener(
this );
   addMouseMotionListener(
this );
  }
  
public  Image getImage(){
   
return  image;
  }
  
public   void  setImage( Image image ){
   
this .image  =  image;
   repaint();
  }
  
// 绘制我们的类,简单的在上面画一幅图
   public   void  paintComponent( Graphics graphics ){
   Graphics g 
=  graphics.create();
   g.setColor( Color.white );
   g.fillRect(
0 , 0 , image  !=   null   ?  image.getWidth( this ): 125 ,image  !=   null   ?  image.getHeight( this ): 125 );
   
if ( image  !=   null  )
    g.drawImage(image,
0 , 0 , this );
   
if ( isFocusOwner() )
    g.setColor(Color.red);
   
else
    g.setColor(Color.black);
   
// 画边框,如果是焦点获得者,边框为红色,否则为黑色
   g.drawRect( 0 , 0 , image  !=   null   ?  image.getWidth( this ): 125 ,image  !=   null   ?  image.getHeight( this ): 125 );
   g.dispose();
  }
  
public   void  focusGained( FocusEvent e ){
   repaint();
  }
  
public   void  focusLost( FocusEvent e ){
   repaint();
  }
  
public   void  mouseClicked(MouseEvent e) {
   requestFocusInWindow();
  }
  
public   void  mouseEntered(MouseEvent e) { }
  
public   void  mouseExited(MouseEvent e) { }
  
public   void  mousePressed(MouseEvent e) { }
  
public   void  mouseReleased(MouseEvent e) { }

  
public   void  mouseDragged(MouseEvent e){
   JComponent c 
=  (JComponent)e.getSource();
   TransferHandler handler 
=  c.getTransferHandler();
   
// 调用exportAsDrag
   handler.exportAsDrag(c,e,TransferHandler.COPY);
  }
  
public   void  mouseMoved(MouseEvent e){}

 }
 
private   class  TransferablePicture  implements  Transferable{ // 一个用来包装数据的类
// 我们的类只包含有图片类型的数据.DataFlavor.imageFlavor 是DataFlavor定义的一个DataFlavor类型,因为图片常用,所以它自带有这种类型,不用我们自己定义.以后再看如何自己定义
  DataFlavor flavors[]  =  { DataFlavor.imageFlavor };
  Image image;
  
public  TransferablePicture( Image image ){
   
this .image  =  image;
  }
  
public  DataFlavor[] getTransferDataFlavors(){ // 返回我们的Transferable包含哪些数据类型
    return  flavors;
  }
  
public  Object getTransferData(DataFlavor flavor){ // 根据参数返回数据
    if ( flavor.equals(DataFlavor.imageFlavor) )
    
return  image;
   
return   null ;
  }
  
public   boolean  isDataFlavorSupported(DataFlavor flavor){
   
return  flavor.equals(DataFlavor.imageFlavor);
  }
  
 }
 
private   class  PictureTransferHandler  extends  TransferHandler{
  
public  Transferable createTransferable( JComponent c ){
   PictureComponent pc 
=  (PictureComponent)c;
   
return   new  TransferablePicture( pc.getImage() ); // 调用构造函数以包装数据,将我们要包装的数据以参数形式传入
  }
  
public   boolean  canImport(JComponent c,DataFlavor[] flavors){ // 判断是否可以导入数据
    for (DataFlavor flavor : flavors){
    
if (flavor.equals(DataFlavor.imageFlavor))
     
return   true ;
   }
   
return   false ;
  }
  
public   boolean  importData( JComponent c, Transferable t){ // 导入数据
    if ( canImport(c,t.getTransferDataFlavors() ) ){ // 如前所说,调用了getTransferDataFlavors() 
    PictureComponent pc  =  (PictureComponent)c;
    
try { // 取得我们需要类型的的数据
     Image image  =  (Image)t.getTransferData(DataFlavor.imageFlavor);
     pc.setImage( image );
     
return   true ;
    }
catch ( UnsupportedFlavorException e ){
     e.printStackTrace();
    }
catch ( IOException e ){
     e.printStackTrace();
    }    
   }
   
return   false ;
  }
  
public   void  exportDone(JComponent c, Transferable data,  int  action){
   
// 传完数据以后,要判断是移动还是复制,然后决定要不要删除拖放源的数据
   PictureComponent picture  =  (PictureComponent)c;
   
if ( action  ==  MOVE ){
    picture.setImage(
null );
   }
  }
  
public   int  getSourceActions(JComponent c){
   
return  COPY_OR_MOVE;
  }
 }
 
public   static   void  main(String[] args) 
 {
  
new  PictureDnd();
 }
}

再来看如何使用剪贴板和同时传输多种数据类型

import  java.awt. * ;
import  javax.swing. * ;
import  java.awt.event. * ;
import  javax.swing.event. * ;
import  java.awt.dnd. * ;
import  java.awt.datatransfer. * ;
import  java.io. * ;
class  ClipboardTest2 
{
 JFrame mainFrame;
 JPanel mainPanel;
 JButton button;
 Clipboard cb;
// 定义一个剪贴板
  public  ClipboardTest2() {
  mainFrame 
=   new  JFrame (  );
  mainPanel 
=   new  JPanel ();
  button 
=   new  JButton ( " Button " );
  button.setIcon( 
new  ImageIcon( " candle.png " ) );

  cb 
=  Toolkit.getDefaultToolkit().getSystemClipboard(); // 取得系统的剪贴板
  button.addActionListener(  new  ActionListener(){
   
public   void  actionPerformed( ActionEvent e){
    ButtonTextAndImageTransferable btait 
=
     
new  ButtonTextAndImageTransferable(button);
   
// 设置剪贴板的内容,第一个参数是Transferable类型的,第二个是ClipboardOwner
    cb.setContents( btait,btait );
   }
  });

  mainPanel.add( button );
  mainFrame.getContentPane().add( mainPanel );
  mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  mainFrame.pack();
  mainFrame.setLocationRelativeTo(
null );
  mainFrame.setVisible( 
true  );
 }
 
public   static   void  main(String[] args) 
 {
  
new  ClipboardTest2();
 }
}
class  ButtonTextAndImageTransferable  extends  ImageIcon  implements  Transferable,ClipboardOwner{
 DataFlavor[] flavors;
 JButton button;
 
public   void  lostOwnership(Clipboard clipboard, Transferable contents){
  System.out.println( 
" lostownership "  ); // ClipboardOwner里的唯一的方法
 }
 
public  ButtonTextAndImageTransferable( JButton button){
     flavors 
=   new  DataFlavor[ 2 ];
  flavors[
0 =   DataFlavor.stringFlavor;
  flavors[
1 =   DataFlavor.imageFlavor;
  
this .button  =  button ;
 }
// 这个数组说明我们的Transferable既有文字,又有图片
  public  DataFlavor[] getTransferDataFlavors(){  
  
return  flavors;
 }
 
public  Object getTransferData(DataFlavor flavor){
  
if ( flavor.equals( flavors[ 0 ] ) ) // 根据参数决定返回的数据
  {
   
return  button.getText();
  }
else {
   
if ( flavor.equals( flavors[ 1 ] ) ){
    ImageIcon icon 
=  (ImageIcon)button.getIcon();
    
return  icon.getImage();
   }
  }
  
return   null ;
 }
 
public   boolean  isDataFlavorSupported(DataFlavor flavor){
  
if ( flavor.equals( flavors[ 0 ] )  ||
   flavor.equals( flavors[
1 ] ))
    
return   true ;
  
return   false ;
 }
}

运行之后,点击button,图片和文字就复制到剪贴板,到word里,选菜单的编辑-选择性粘贴就可以粘贴图片或文字

====================================

欢迎评论,欢迎指正,欢迎交流 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值