Java剪贴板未与系统共享

Java剪贴板未与系统共享,java,clipboard,Java,Clipboard,我有一个格式为HTML的JEditorPane字段,当我将其复制到剪贴板时,系统将丢失所有换行符 窗格中的文本: <html> <head> </head> <body> <p> Bonjour,<br><br>Merci de faire les actions ci-dessous:<br><br>1- Sauvegarder le fi

我有一个格式为HTML的JEditorPane字段,当我将其复制到剪贴板时,系统将丢失所有换行符

窗格中的文本:

 <html>
  <head>
  </head>
  <body>
    <p>
      Bonjour,<br><br>Merci de faire les actions ci-dessous:<br><br>1- 
      Sauvegarder le fichier AAAA<br>2- Remplacer le contenu du 
      fichier AAAA par le contenu fichier 
      BBBBB <br>3- Relancer au step plant&#233;<br><br>Cordialement,<br>
    </p>
  </body>
</html>
所以,我截取了Ctrl+C:

public void keyPressed(KeyEvent e) {
//Modify clipboard Ctrl+C
if ((e.getKeyCode() == KeyEvent.VK_C) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
super.keyPressed(e);
genericFunctions.setClipboardText(edSolution.getText());//see function bellow
}
我尝试过修改它:

static void setClipboardText(String s) {
  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  StringSelection stringSelection = new StringSelection(s);
  clipboard.setContents(stringSelection, stringSelection);
}
但是剪贴板中的文本没有改变

奇怪的是,如果我使用下面的函数:

 static void setClipboardText(String s) {
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    Clipboard selection = Toolkit.getDefaultToolkit().getSystemSelection();
    StringSelection stringSelection = new StringSelection(s);
    StringSelection stringS = new StringSelection(s);
    clipboard.setContents(stringSelection, stringSelection);
    selection.setContents(stringS, stringS);//error AWT-EventQueue-0" java.lang.NullPointerException"
}
即使我得到了一个NullPointerException,剪贴板还是用新值进行了很好的修改

有人能告诉我为什么剪贴板只在错误发生后而不是之前刷新吗? 我如何向系统宣布剪贴板已更改并应读取它


JDK8 v1.8.0_251

我猜测“默认”复制操作只会将编辑器中的文本复制为“纯文本”——或者至少,这是接收者可用的选项之一,并将其作为首选项(我无法轻松访问Java源代码以深入了解默认实现)

如中所述,您可以覆盖默认的“复制”操作并插入自己的工作流/格式

这是一个非常简单的概念示例。当我用它复制和粘贴文本时,我得到了完整的HTML文本

如果您不想简单地获取带换行符的文本,您必须自己解释内容并生成合适的输出
String
,那么您可以使用
DataFlavor.stringFlavor
作为主要数据样式,但这已经超出了范围

import java.awt.BorderLayout;
import java.awt.Dimension;
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.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringBufferInputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JEditorPane editorPane;

        public TestPane() {

            URL url = getClass().getResource("Text.html");
            editorPane = new JEditorPane();
            editorPane.setContentType("html/text");
            try {
                editorPane.setPage(url);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            editorPane.getActionMap().put("copy", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String text = editorPane.getText();
                    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                    clipboard.setContents(new HtmlSelection(text), null);
                }
            });
            setLayout(new BorderLayout());
            add(new JScrollPane(editorPane));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }

    private static class HtmlSelection implements Transferable {

        private static List<DataFlavor> htmlFlavors = new ArrayList<>(3);

        static {

            try {
                htmlFlavors.add(new DataFlavor("text/html;class=java.lang.String"));
                htmlFlavors.add(new DataFlavor("text/html;class=java.io.Reader"));
                htmlFlavors.add(new DataFlavor("text/html;charset=unicode;class=java.io.InputStream"));
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }

        }

        private String html;

        public HtmlSelection(String html) {
            this.html = html;
        }

        public DataFlavor[] getTransferDataFlavors() {
            return (DataFlavor[]) htmlFlavors.toArray(new DataFlavor[htmlFlavors.size()]);
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return htmlFlavors.contains(flavor);
        }

        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
            if (String.class.equals(flavor.getRepresentationClass())) {
                return html;
            } else if (Reader.class.equals(flavor.getRepresentationClass())) {
                return new StringReader(html);
            } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
                return new StringBufferInputStream(html);
            }
            throw new UnsupportedFlavorException(flavor);
        }
    }
}
问题是,它没有考虑样式化标记。乔伊

所以,在多读了一点之后,我发现-

所以,我修改了原始代码,使用了与此相同的概念

editorPane.getActionMap().put("copy", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        String text = editorPane.getText();
        text = formattedPlainText(text);
        StringSelection selection = new StringSelection(text);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(selection, selection);
    }

    protected String formattedPlainText(String text) {
        final StringBuilder sb = new StringBuilder();
        HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() {
            public boolean readyForNewline;

            @Override
            public void handleText(final char[] data, final int pos) {
                String s = new String(data);
                sb.append(s.trim());
                readyForNewline = true;
            }

            @Override
            public void handleStartTag(final HTML.Tag t, final MutableAttributeSet a, final int pos) {
                if (readyForNewline && (t == HTML.Tag.DIV || t == HTML.Tag.BR || t == HTML.Tag.P)) {
                    sb.append("\n");
                    readyForNewline = false;
                }
            }

            @Override
            public void handleSimpleTag(final HTML.Tag t, final MutableAttributeSet a, final int pos) {
                handleStartTag(t, a, pos);
            }
        };
        try {
            new ParserDelegator().parse(new StringReader(text), parserCallback, false);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        return sb.toString();
    }
});
我现在可以在复制文本时得到这个

你好,
谢天谢地,我们行动起来了:
1-Sauvegarder le fichier AAAA
2 -遗赠者 3-Relancer au step planté
诚意

卡韦
这两个例子将忽略选择,并将复制整个文本-这是我的时间限制。如果需要,从
样式文档
中提取样式化标记并确定如何最好地格式化文本将需要更多的努力。问题可能不是文本如何复制到剪贴板,而是接收者如何将其解释为“如何”它是从剪贴板中提取出来的,这将是接收者和发起者的支持导出选项的一个“种类”和它的兄弟。这两个示例都覆盖了组件的默认“复制”操作,并在其中注入了自己的内容导出逻辑。注意使用自定义的
DataFlavor
,以避免使用有利于HTMLTank you的“纯文本”!我将外部化格式化的纯文本,因为我需要对多个JeditorPane使用相同的功能。
public void exportToClipboard(JComponent comp, Clipboard clipboard,
                              int action) throws IllegalStateException {
    if (comp instanceof JTextComponent) {
        JTextComponent text = (JTextComponent)comp;
        int p0 = text.getSelectionStart();
        int p1 = text.getSelectionEnd();
        if (p0 != p1) {
            try {
                Document doc = text.getDocument();
                String srcData = doc.getText(p0, p1 - p0);
                StringSelection contents =new StringSelection(srcData);

                // this may throw an IllegalStateException,
                // but it will be caught and handled in the
                // action that invoked this method
                clipboard.setContents(contents, null);

                if (action == TransferHandler.MOVE) {
                    doc.remove(p0, p1 - p0);
                }
            } catch (BadLocationException ble) {}
        }
    }
}
editorPane.getActionMap().put("copy", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        String text = editorPane.getText();
        text = formattedPlainText(text);
        StringSelection selection = new StringSelection(text);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(selection, selection);
    }

    protected String formattedPlainText(String text) {
        final StringBuilder sb = new StringBuilder();
        HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() {
            public boolean readyForNewline;

            @Override
            public void handleText(final char[] data, final int pos) {
                String s = new String(data);
                sb.append(s.trim());
                readyForNewline = true;
            }

            @Override
            public void handleStartTag(final HTML.Tag t, final MutableAttributeSet a, final int pos) {
                if (readyForNewline && (t == HTML.Tag.DIV || t == HTML.Tag.BR || t == HTML.Tag.P)) {
                    sb.append("\n");
                    readyForNewline = false;
                }
            }

            @Override
            public void handleSimpleTag(final HTML.Tag t, final MutableAttributeSet a, final int pos) {
                handleStartTag(t, a, pos);
            }
        };
        try {
            new ParserDelegator().parse(new StringReader(text), parserCallback, false);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        return sb.toString();
    }
});