Java 剪贴板未与系统共享
Java clipboard is not shared with system
我有一个格式为 HTML 的 JEditorPane 字段,当我将它复制到剪贴板时,系统会丢失所有换行符。
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é<br><br>Cordialement,<br>
</p>
</body>
</html>
使用 Ctrl + C 复制并在 Notepad++ 中粘贴时,文本为:
Bonjour, Merci de faire les actions ci-dessous: 1- Sauvegarder le fichier AAAA 2- Remplacer le contenu du fichier AAAA par le contenu fichier BBBB 3- Relancer au step planté Cordialement,
所以,我截获了 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 源代码以深入研究默认实现)
如 and Copy jTable row with its grid lines into excel/word documents 中所述,您可以覆盖默认的“复制”操作并插入您自己的 workflow/formatting。
这是一个非常简单的概念示例。当我使用它复制和粘贴文本时,我得到了完整的 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);
}
}
}
已更新
好的,经过一番挖掘,我发现 JEditorPane
使用 JTextComponent
的默认功能将 Document
的内容复制到剪贴板...
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) {}
}
}
}
问题在于,它没有考虑样式化标记。喜悦。
所以,经过更多的阅读,我发现了 - Copying to the clipboard in Java
所以,我修改了原始代码以使用与此相同的概念...
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();
}
});
我现在可以在复制文本时得到这个...
Bonjour,
Merci de faire les actions ci-dessous:
1- Sauvegarder le fichier AAAA
2- Remplacer le contenu du fichier AAAA par le contenu fichier BBBBB
3- Relancer au step planté
Cordialement,
告诫
这两个示例都将忽略选择并复制整个文本 - 这是我时间的限制。如果需要,从 StyledDocument
中提取带样式的标记并确定如何最好地格式化文本
将花费更多的精力
我有一个格式为 HTML 的 JEditorPane 字段,当我将它复制到剪贴板时,系统会丢失所有换行符。
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é<br><br>Cordialement,<br>
</p>
</body>
</html>
使用 Ctrl + C 复制并在 Notepad++ 中粘贴时,文本为:
Bonjour, Merci de faire les actions ci-dessous: 1- Sauvegarder le fichier AAAA 2- Remplacer le contenu du fichier AAAA par le contenu fichier BBBB 3- Relancer au step planté Cordialement,
所以,我截获了 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);
}
}
}
已更新
好的,经过一番挖掘,我发现 JEditorPane
使用 JTextComponent
的默认功能将 Document
的内容复制到剪贴板...
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) {}
}
}
}
问题在于,它没有考虑样式化标记。喜悦。
所以,经过更多的阅读,我发现了 - Copying to the clipboard in Java
所以,我修改了原始代码以使用与此相同的概念...
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();
}
});
我现在可以在复制文本时得到这个...
Bonjour,
Merci de faire les actions ci-dessous:
1- Sauvegarder le fichier AAAA
2- Remplacer le contenu du fichier AAAA par le contenu fichier BBBBB
3- Relancer au step planté
Cordialement,
告诫
这两个示例都将忽略选择并复制整个文本 - 这是我时间的限制。如果需要,从 StyledDocument
中提取带样式的标记并确定如何最好地格式化文本