前一陣做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帶有對應的功能了。