java中的dnd

來源:互聯網
上載者:User

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裡,選菜單的編輯-選擇性粘貼就可以粘貼圖片或文字

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

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/XXKKFF/archive/2007/01/11/1480506.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.