Java 如何在JTextPane中粘贴时保留源文本样式?

Java 如何在JTextPane中粘贴时保留源文本样式?,java,swing,jtextpane,Java,Swing,Jtextpane,使用JavaSwing,我正在使用RTFEditorKit()创建一个简单的.rtf文件编辑器应用程序。我正在使用JTextPane。我为粗体、斜体和下划线文本添加了代码 我的问题场景: 我有两行文字,第一行是粗体字,第二行是斜体字。 将某些文本从第一行(粗体)复制到第二行时,将粗体文本粘贴到第二行后,将以斜体显示 预期场景:粘贴后应为粗体样式,应保留样式。 如何在JavaSwing中实现这一点?有人能帮忙吗?谢谢。这是几年前我在论坛上找到的一些旧代码 它将单个属性与文本一起复制 不知道它是否与

使用JavaSwing,我正在使用RTFEditorKit()创建一个简单的.rtf文件编辑器应用程序。我正在使用JTextPane。我为粗体、斜体和下划线文本添加了代码

我的问题场景: 我有两行文字,第一行是粗体字,第二行是斜体字。 将某些文本从第一行(粗体)复制到第二行时,将粗体文本粘贴到第二行后,将以斜体显示

预期场景:粘贴后应为粗体样式,应保留样式。
如何在JavaSwing中实现这一点?有人能帮忙吗?谢谢。

这是几年前我在论坛上找到的一些旧代码

它将单个属性与文本一起复制

不知道它是否与RTFEditorKit一起工作:

/*
    crwood:
    http://forum.java.sun.com/thread.jspa?threadID=5137992&tstart=0
*/

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.IOException;
import java.text.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.text.*;

public class StyleTransfer {
    private JPanel getContent() {
        JTextPane left = new JTextPane();
        initialize(left);
        left.setDragEnabled(true);
        left.setTransferHandler(new StyleTransferHandler());
        JTextPane right = new JTextPane();
        right.setDragEnabled(true);
        right.setTransferHandler(new StyleTransferHandler());
        JPanel panel = new JPanel(new GridLayout(0,1));
        panel.add(new JScrollPane(left));
        panel.add(new JScrollPane(right));
        panel.add( new JScrollPane( new JTextArea() ) );
        return panel;
    }

    private void initialize(JTextPane textPane) {
        String text = "This component models paragraphs that are composed of " +
            "runs of character level attributes. Each paragraph may have a " +
            "logical style attached to it which contains the default attributes " +
            "to use if not overridden by attributes set on the paragraph or " +
            "character run. Components and images may be embedded in the flow " +
            "of text."; // 0 - 319
        StyledDocument doc = textPane.getStyledDocument();
        createStyles(doc);
        setContent(doc, text);
        styleContent(doc);
    }

    private void createStyles(StyledDocument doc) {
        Style baseStyle = doc.addStyle("base", null);
        StyleConstants.setFontFamily(baseStyle, "Lucida Sans Unicode");
        StyleConstants.setFontSize(baseStyle, 18);
        StyleConstants.setLeftIndent(baseStyle, 10f);

        Style style = doc.addStyle("bold", baseStyle);
        StyleConstants.setBold(style, true);

        style = doc.addStyle("italic", baseStyle);
        StyleConstants.setItalic(style, true);

        style = doc.addStyle("blue", baseStyle);
        StyleConstants.setForeground(style, Color.blue);

        style = doc.addStyle("underline", baseStyle);
        StyleConstants.setUnderline(style, true);

        style = doc.addStyle("green", baseStyle);
        StyleConstants.setForeground(style, Color.green.darker());
        StyleConstants.setUnderline(style, true);

        style = doc.addStyle("highlight", baseStyle);
        StyleConstants.setForeground(style, Color.yellow);
        StyleConstants.setBackground(style, Color.black);
    }

    private void setContent(StyledDocument doc, String text) {
        try {
            doc.insertString(0, text, doc.getStyle("base"));
        } catch(BadLocationException e) {
            System.out.println(e);
        }
    }

    private void styleContent(StyledDocument doc) {
        String[] names = {
            "underline", "highlight", "blue", "italic",
            "green", "green", "bold", "bold"
        };
        int[] starts  = { 22, 62, 116, 164, 233, 246, 261, 276 };
        int[] lengths = { 10, 26,  13,  18,   9,   9,  10,   6 };
        Style style = doc.getStyle("base");
        doc.setLogicalStyle(0, style);
        for(int j = 0; j < names.length; j++) {
            style = doc.getStyle(names[j]);
            doc.setCharacterAttributes(starts[j], lengths[j], style, false);
        }
    }

    public JMenuBar getMenuBar () {
        JMenuItem menuItem = null;
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Edit");
        menu.setMnemonic(KeyEvent.VK_E);
        menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
        menuItem.setText("Cut");
        menuItem.setMnemonic(KeyEvent.VK_T);
        menu.add(menuItem);
        menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
        menuItem.setText("Copy");
        menuItem.setMnemonic(KeyEvent.VK_C);
        menu.add(menuItem);
        menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
        menuItem.setText("Paste");
        menuItem.setMnemonic(KeyEvent.VK_P);
        menu.add(menuItem);
        menuBar.add(menu);
        return menuBar;
    }

    public static void main(String[] args) {
        System.setProperty("swing.aatext", "true");
        StyleTransfer test = new StyleTransfer();
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setJMenuBar(test.getMenuBar());
        f.getContentPane().add(test.getContent());
        f.setSize(500,500);
        f.setLocation(100,50);
        f.setVisible(true);
    }
}

class StyleTransferHandler extends TransferHandler {
    String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
                          ";class=StyledString";
    DataFlavor styledStringFlavor;

    public StyleTransferHandler() {
        try {
            styledStringFlavor = new DataFlavor(mimeType);
        } catch(ClassNotFoundException e) {
            System.out.println("Unable to create styledStringFlavor");
        }
    }

    public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
        for(int j = 0; j < transferFlavors.length; j++) {
            if(styledStringFlavor.equals(transferFlavors[j]))
                return true;
        }
        return false;
    }

    protected Transferable createTransferable(JComponent c) {
        JTextPane textPane = (JTextPane)c;
        int start = textPane.getSelectionStart();
        int end = textPane.getSelectionEnd();
        StyledString ss = new StyledString("");
        if(start != -1 && start != end) {
            String text = textPane.getSelectedText();
            ss = new StyledString(text);
            StyledDocument doc = textPane.getStyledDocument();
            extractAttributes(doc, start, end, ss);
        }
        System.out.println(ss);
        return new StyledStringTransferable(ss);
    }

    private void extractAttributes(StyledDocument doc, int selectionStart,
                                   int selectionEnd, StyledString styledStr) {
        int pos = selectionStart;
        styledStr.logicalStyle = doc.getLogicalStyle(pos);
        while(pos < selectionEnd) {
            Element element = doc.getCharacterElement(pos);
            AttributeSet attrs = element.getAttributes();
            int endOffset = element.getEndOffset();
            int end = (endOffset < selectionEnd) ? endOffset : selectionEnd;
            styledStr.addAttributes(attrs, pos, end);
            pos = end;
        }
    }

    /**
     * MOVE is not supported in superclass implementation
     * and exportDone is implemented to do nothing - see api.
     */
    public void exportAsDrag(JComponent comp, InputEvent e, int action) {
        super.exportAsDrag(comp, e, action);
        Clipboard clip = comp.getToolkit().getSystemClipboard();
        exportDone(comp, clip, action);
    }

    /**
     * MOVE is not supported in superclass implementation
     * and exportDone is implemented to do nothing - see api.
     */
    public void exportToClipboard(JComponent comp, Clipboard clip, int action) {
        super.exportToClipboard(comp, clip, action);
        exportDone(comp, clip, action);
    }

    public void exportDone(JComponent comp, Clipboard clip, int action) {
        JTextPane textPane = (JTextPane)comp;
        if(action == MOVE) {
            int offset = textPane.getSelectionStart();
            int length = textPane.getSelectionEnd() - offset;
            StyledDocument doc = textPane.getStyledDocument();
            try {
                doc.remove(offset, length);
            } catch(BadLocationException e) {
                System.out.println(e);
            }
        }
    }

    public int getSourceActions(JComponent c) {
        return COPY_OR_MOVE;
    }

    public boolean importData(JComponent comp, Transferable t) {
        if(canImport(comp, t.getTransferDataFlavors())) {
            StyledString styledStr = null;
            try {
                styledStr = (StyledString)t.getTransferData(styledStringFlavor);
                List attrs = styledStr.attrs;
                List locs = styledStr.locs;
                JTextPane textPane = (JTextPane)comp;
                int pos = textPane.getCaretPosition();
                StyledDocument doc = textPane.getStyledDocument();
                Style logicalStyle = styledStr.logicalStyle;
                // Insert the text.
                try {
                    doc.insertString(pos, styledStr.text, logicalStyle);
                } catch(BadLocationException e) {
                    System.out.println(e);
                }
                // Appy the style runs to the inserted text.
                for(int j = 0; j < attrs.size(); j++) {
                    AttributeSet as = (AttributeSet)attrs.get(j);
                    Location loc = (Location)locs.get(j);
                    doc.setCharacterAttributes(pos, loc.length, as, false);
                    pos += loc.length;
                }
                return true;
            } catch(UnsupportedFlavorException ufe) {
                System.out.println("importData UnsupportedFlavor: " +
                                    ufe.getMessage());
            } catch(IOException ioe) {
                System.out.println("importData IO Error: " + ioe.getMessage());
            }
        }
        return false;
    }

    class StyledStringTransferable implements Transferable {
        private StyledString styledString;

        StyledStringTransferable(StyledString ss) {
            styledString = ss;
        }

        public Object getTransferData(DataFlavor flavor)
                                  throws UnsupportedFlavorException {
            if(!isDataFlavorSupported(flavor))
                throw new UnsupportedFlavorException(flavor);
            return styledString;
        }

        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[] { styledStringFlavor };
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return styledStringFlavor.equals(flavor);
        }

        public String toString() {
            return "StyledStringTransferable: " + styledString;
        }
    }
}

class StyledString {
    String text;
    List attrs;
    List locs;
    Style logicalStyle;

    public StyledString(String text) {
        this.text = text;
        attrs = new ArrayList();
        locs  = new ArrayList();
    }

    public void addAttributes(AttributeSet atts, int start, int end) {
        attrs.add(atts);
        locs.add(new Location(start, end));
    }

    public String toString() {
        StringBuffer sb = new StringBuffer("StyledString[");
        for(int j = 0; j < attrs.size(); j++) {
            sb.append("Attributes[");
            Enumeration e = ((AttributeSet)attrs.get(j)).getAttributeNames();
            while(e.hasMoreElements()) {
                Object key = e.nextElement();
                Object value = ((AttributeSet)attrs.get(j)).getAttribute(key);
                sb.append("key:" + key + ",value:" + value + ";");
            }
            sb.append("]");
            sb.append(" for " + locs.get(j));
            if(j < attrs.size()-1)
                sb.append("\n");
        }
        System.out.println(sb);
        return sb.toString();
    }
}

class Location {
    int start;
    int length;

    public Location(int start, int end) {
        this.start = start;
        length = end - start;
    }

    public String toString() {
        return "Location[start:" + start + ",length:" + length + "]";
    }
}
/*
克伍德:
http://forum.java.sun.com/thread.jspa?threadID=5137992&tstart=0
*/
导入java.awt.*;
导入java.awt.datatransfer.*;
导入java.awt.event.*;
导入java.io.IOException;
导入java.text.*;
导入java.util.*;
导入java.util.List;
导入javax.swing.*;
导入javax.swing.text.*;
公共类样式转换{
私有JPanel getContent(){
JTextPane left=新的JTextPane();
初始化(左);
左。设置为已禁用(true);
setTransferHandler(新样式TransferHandler());
JTextPane right=新的JTextPane();
对。setDragEnabled(true);
右。setTransferHandler(新样式TransferHandler());
JPanel面板=新JPanel(新网格布局(0,1));
添加(新的JScrollPane(左));
panel.add(新的JScrollPane(右));
add(新的JScrollPane(新的JTextArea());
返回面板;
}
私有void初始化(JTextPane textPane){
String text=“此组件对由以下内容组成的段落进行建模”+
“字符级属性的运行。每个段落可能有一个”+
“附加到包含默认属性的逻辑样式”+
“如果未被段落或上设置的属性覆盖,则使用”+
“字符运行。组件和图像可能嵌入到流中”+
“的文本。”;//0-319
StyledDocument doc=textPane.getStyledDocument();
创建样式(doc);
设置内容(文档、文本);
样式内容(doc);
}
私有void createStyles(样式文档文档){
Style baseStyle=doc.addStyle(“base”,空);
setFontFamily(baseStyle,“Lucida Sans Unicode”);
setFontSize(baseStyle,18);
setLeftIndent(baseStyle,10f);
样式样式=文件添加样式(“粗体”,基本样式);
StyleConstants.setBold(style,true);
style=doc.addStyle(“斜体”,baseStyle);
setItalic(style,true);
style=doc.addStyle(“蓝色”,baseStyle);
设置前景(样式、颜色、蓝色);
style=doc.addStyle(“下划线”,baseStyle);
setUnderline(style,true);
style=doc.addStyle(“绿色”,baseStyle);
setForeground(style,Color.green.darker());
setUnderline(style,true);
style=doc.addStyle(“突出显示”,baseStyle);
设置前景(样式、颜色、黄色);
StyleConstants.setBackground(样式、颜色、黑色);
}
私有void setContent(样式文档文档,字符串文本){
试一试{
doc.insertString(0,text,doc.getStyle(“base”);
}捕获(错误位置异常e){
系统输出打印ln(e);
}
}
私有void样式内容(样式文档文档){
字符串[]名称={
“下划线”、“高光”、“蓝色”、“斜体”,
“绿色”、“绿色”、“粗体”、“粗体”
};
int[]开始={22,62,116,164,233,246,261,276};
int[]长度={10,26,13,18,9,9,10,6};
Style Style=doc.getStyle(“基”);
文档setLogicalStyle(0,样式);
对于(int j=0;j