支持對象的剪切板

前一陣做JTextPane的東西,一直不知道剪切板怎麼用。後來研究了一下,知道怎麼用剪切板分別複製粘貼文字和圖像了。但是如果要同時複製圖像和文字就不會了。

看了半天API,應該是支持剪切對象的,但是不知道具體怎麼操作。後來看了一下《Java核心技術 卷2 原書第八版》中的內容(P558),按照上面的代碼修改了一下,終於能夠剪切和粘貼圖文混排的內容了。


代碼如下:

package cn.com.microproposal.test.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

/**
 * 轉載請註明出處。Blog : http://blog.csdn.net/levelmini/article/details/27661703
 * @author Aranya
 *
 */
public class SerialTransferTest {
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable(){
			public void run(){
				JFrame frame = new SerialTransferFrame();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setVisible(true);
			}
		});
	}
}

class SerialTransferFrame extends JFrame {

	private static final long serialVersionUID = 6239828970658861018L;
	
	private JTextPane textpane;
	public SerialTransferFrame() {
		textpane = new JTextPane();
		add(textpane,BorderLayout.CENTER);
		JPanel panel = new JPanel();
		
		JButton copy = new JButton("Copy");
		panel.add(copy);
		JButton paste = new JButton("Paste");
		panel.add(paste);
		copy.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e){
				copy();
			}
		});
		paste.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e){
				paste();
			}
		});
		add(panel,BorderLayout.SOUTH);
		pack();
	}
	
	private void copy() {
		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		
		int start = textpane.getSelectionStart();
		int end = textpane.getSelectionEnd();
		
		if (start == end) {  //如果相等則說明沒有選中任何內容
			return;
		}
		//將選中的內容封裝到對象中
		StyledDocument doc = textpane.getStyledDocument();
		MyImgAndTextObject object = new MyImgAndTextObject();
		for (int i = start; i < end; i++) {
			Element el = doc.getCharacterElement(i);
			if (el.getName().equals("content")) {
				try {
					object.put(textpane.getText(i, 1));
				} catch (BadLocationException e) {
					e.printStackTrace();
				}
			}
			if (el.getName().equals("icon")) {
				Icon icon = StyleConstants.getIcon(el.getAttributes());
				object.put(icon);				
			}
		}
		
		SerialTransferable selection = new SerialTransferable(object);
		clipboard.setContents(selection, null);
	}
	
	private void paste() {
		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		StyledDocument doc = textpane.getStyledDocument(); 
		int start = textpane.getSelectionStart();
		int end = textpane.getSelectionEnd();
		try {
			if (start < end) {	//如果有選中的數據則移除選中的數據
				doc.remove(start, end-start);
			}
			DataFlavor img_flavor = DataFlavor.imageFlavor;
			DataFlavor text_flavor = DataFlavor.stringFlavor; 
			DataFlavor obj_flavor = new DataFlavor("application/x-java-serialized-object;class=cn.com.microproposal.test.gui.MyImgAndTextObject");
			if (clipboard.isDataFlavorAvailable(obj_flavor)) {	//這個判斷一定要寫在前面,否則會多粘貼出來東西。
				MyImgAndTextObject object = (MyImgAndTextObject) clipboard.getData(obj_flavor);
				int i = 0;
				for (Object obj : object) {
					if (obj instanceof String) {
						doc.insertString(start+i, obj+"", null);
					}
					if (obj instanceof ImageIcon) {
						textpane.insertIcon((ImageIcon)obj);
					}
					i++;
				}
			}else if (clipboard.isDataFlavorAvailable(img_flavor)) {
				BufferedImage img = (BufferedImage) clipboard.getData(img_flavor);
				Icon icon = new ImageIcon(img);
				textpane.insertIcon(icon);
			} else if (clipboard.isDataFlavorAvailable(text_flavor)) {
				String str = (String) clipboard.getData(text_flavor);
				doc.insertString(start, str, null);
			} 
		} catch (ClassNotFoundException e) {
			JOptionPane.showMessageDialog(this, e);
		} catch (UnsupportedFlavorException e) {
			JOptionPane.showMessageDialog(this, e);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this, e);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}

	}
}

/**
 * 支持傳輸對象的Transfer
 * @author Aranya
 */
class SerialTransferable implements Transferable {

	Object obj ;
	public SerialTransferable(Serializable o) {
		obj = o;
	}
	
	@Override
	public DataFlavor[] getTransferDataFlavors() {
		DataFlavor [] flavors = new DataFlavor[2];
		Class<?> type = obj.getClass();
		String mimeType = "application/x-java-serialized-object;class="+type.getName();
		try {
			flavors[0] = new DataFlavor(mimeType);
			flavors[1] = DataFlavor.stringFlavor;
			return flavors;
		} catch (ClassNotFoundException e) {
			return new DataFlavor[0];
		}
		
	}

	@Override
	public boolean isDataFlavorSupported(DataFlavor flavor) {
		return DataFlavor.stringFlavor.equals(flavor)
				|| "application".equals(flavor.getPrimaryType())
				&& "x-java-serialized-object".equals(flavor.getSubType())
				&&flavor.getRepresentationClass().isAssignableFrom(obj.getClass());
	}

	@Override
	public Object getTransferData(DataFlavor flavor)
			throws UnsupportedFlavorException, IOException {
		if (!isDataFlavorSupported(flavor)) {
			throw new UnsupportedFlavorException(flavor);
		}
		if (DataFlavor.stringFlavor.equals(flavor)) {
			return obj.toString();
		}
		return obj;
	}
}
/**
 * 封裝圖文的對象
 * @author Aranya
 */
class MyImgAndTextObject implements Serializable,Iterable<Object>{

	private static final long serialVersionUID = -4660396449705937711L;
	
	private List<Object> content = new ArrayList<Object>();
	
	public boolean put(Object o){
		return content.add(o);
	}
	public List<Object> get(){
		return content;
	}
	@Override
	public Iterator<Object> iterator() {
		return content.iterator();
	}
}


擴展:自己寫一個類繼承JTextPane,然後Override這個類的copy()方法和paste()方法,實現步驟就按照這裏面的copy()方法和paste()方法,就可以讓你的TextPane帶有對應的功能了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章