【问题标题】:How to preserve the source text style while pasting in JTextPane?在 JTextPane 中粘贴时如何保留源文本样式?
【发布时间】:2018-10-25 09:58:58
【问题描述】:

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

我的问题场景: 我有两行文字,第一行文字充满粗体风格,第二行文字充满斜体风格。 在将一些文本从第一行(粗体)复制到第二行时,将粗体文本粘贴到第二行后,它以斜体样式显示。

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

【问题讨论】:

    标签: java swing jtextpane


    【解决方案1】:

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

    它使用文本复制单个属性。

    不知道它是否适用于 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 + "]";
        }
    }
    

    【讨论】:

    • 您好,能否请您提供一个准确的复制粘贴代码以保留源文本样式,对不起,我是 java 新手。
    • 我确实给了你确切的代码。您可以复制/粘贴/编译和测试。 I am a newbie to java - 那么也许你需要从更简单的开始。我们不是在这里为您编写代码。您已获得似乎可以执行您想要的操作的代码。你需要花时间去理解它。
    • 感谢您的建议,您的代码抛出空指针异常,这就是我问的原因,无论如何谢谢
    • @AbiSaran,对我来说很好(在 Windows 7 上使用 JDK8),否则我不会发布代码。您所做的只是 1)选择一些文本 2)单击“编辑”,然后单击“复制” 3)单击第二个文本窗格 4)单击“编辑”,然后单击“粘贴”。 your code throws null pointer exception - 您在原始评论中没有说明,也没有说明您用来导致 NPE 的步骤。我们不是读心术的人。我们猜不出你在做什么。我不知道你是做错了什么还是平台问题。
    • 对不起,我之前的评论发错了,我使用的是JDK 8和windows 10,我会再次调试和检查,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 2018-02-16
    • 2014-07-07
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多