Java 此解决方案通过连续字符串比较来检测更改。通过读取并访问剪贴板,我希望此代码对其他应用程序造成的干扰比例如获取剪贴板的所有权更少
欢迎提出建议Java 此解决方案通过连续字符串比较来检测更改。通过读取并访问剪贴板,我希望此代码对其他应用程序造成的干扰比例如获取剪贴板的所有权更少,java,clipboard,Java,Clipboard,欢迎提出建议 packagegui; 导入java.awt.HeadlessException; 导入java.awt.Toolkit; 导入java.awt.datatransfer.Clipboard; 导入java.awt.datatransfer.DataFlavor; 导入java.awt.datatransfer.UnsupportedFlavorException; 导入java.io.IOException; 导入java.util.array; 导入java.util.List
packagegui;
导入java.awt.HeadlessException;
导入java.awt.Toolkit;
导入java.awt.datatransfer.Clipboard;
导入java.awt.datatransfer.DataFlavor;
导入java.awt.datatransfer.UnsupportedFlavorException;
导入java.io.IOException;
导入java.util.array;
导入java.util.List;
导入java.util.Observable;
/**
*@作者Matthias Hinz
*/
类ClipboardTextListener扩展了Observable实现Runnable{
剪贴板sysClip=Toolkit.getDefaultToolkit().getSystemClipboard();
private volatile boolean running=true;
公共无效终止(){
运行=错误;
}
公开募捐{
System.out.println(“侦听剪贴板…”);
//第一个输出将在检测到非空文本时进行
字符串recentContent=“”;
//连续执行从剪贴板读取
(跑步时){
试一试{
睡眠(200);
}捕捉(中断异常e){
e、 printStackTrace();
}
试一试{
//请求支持哪种数据风格
List flavors=Arrays.asList(sysClip.getAvailableDataFlavors());
//此实现仅支持字符串风格
if(flavors.contains(DataFlavor.stringFlavor)){
字符串数据=(字符串)sysClip.getData(DataFlavor.stringFlavor);
如果(!data.equals(recentContent)){
最近内容=数据;
//检测到剪贴板更改时,执行您想执行的任何操作,例如:
System.out.println(“检测到新剪贴板文本:“+数据”);
setChanged();
观察员(数据);
}
}
}捕捉(无头例外e1){
e1.printStackTrace();
}捕获(不支持的LavorException e1){
e1.printStackTrace();
}捕获(IOE1异常){
e1.printStackTrace();
}
}
}
公共静态void main(字符串[]args){
ClipboardTextListener b=新的ClipboardTextListener();
螺纹=新螺纹(b);
thread.start();
}
}
我不完全确定这是否是正确和最佳的方法,但至少对我来说效果不错。
下面是剪贴板处理程序的示例,它实现了剪贴板所有者接口,并在每次失去所有权时读取剪贴板缓冲区。然后,当新条目再次进入剪贴板读取时,它将重新获得所有权,以便能够在下次丢失它。它还允许实用地设置剪贴板内容(在下面的示例中提供了新的标准输入行)
公共静态类ClipboardHandler实现ClipboardOwner,Runnable{
私有最终记录器Logger=LoggerFactory.getLogger(getClass());
私有最终剪贴板剪贴板=Toolkit.getDefaultToolkit().getSystemClipboard();
私人最终消费者;
公共剪贴簿处理程序(使用者缓冲区使用者){
this.bufferConsumer=bufferConsumer;
}
@凌驾
公共无效丢失(剪贴板,可转移未使用){
可转移内容=剪贴板.getContents(此);
if(contents.isDataFlavorSupported(DataFlavor.stringFlavor)){
试一试{
String=(String)contents.getTransferData(DataFlavor.stringFlavor);
接受(字符串);
}捕获(例外e){
logger.error(“无法读取剪贴板缓冲区。”,e);
}
}
获取所有权(内容);
}
@凌驾
公开募捐{
可转移=剪贴板.getContents(此);
所有权(可转让);
}
公共void setBuffer(字符串缓冲区){
获取所有权(新字符串选择(缓冲区));
}
私有所有权(可转让){
剪贴板。设置内容(可转让,本);
}
}
公共静态void main(字符串[]args){
ClipboardHandler ClipboardHandler=新的ClipboardHandler(System.out::println);
调用器(clipboardHandler);
扫描仪=新的扫描仪(System.in);
while(scanner.hasNextLine()){
字符串缓冲区=scanner.nextLine();
如果(!buffer.trim().isEmpty()){
setBuffer(缓冲区);
}
}
}
FlavorListener在MacOS(JRE8)中不起作用,因此轮询是一种方法。Matthias Hinz给出了一个没有摇摆的投票解决方案。以下是我的解决方案,它使用Swing在JTextPane中显示实时剪贴板内容:
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
public class ClipboardWatcher {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame(ClipboardWatcher.class.getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextPane tp = new JTextPane();
tp.setPreferredSize(new Dimension(384, 256));
f.getContentPane().add(new JScrollPane(tp));
f.pack();
f.setVisible(true);
new Timer(200, e -> {
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
DataFlavor df = DataFlavor.stringFlavor;
if (c.isDataFlavorAvailable(df)) {
try {
String data = c.getData(df).toString();
if (!data.equals(_lastData))
tp.setText(_lastData = data);
} catch (Exception ex) {
System.err.println(ex);
}
}
}).start();
});
}
private static String _lastData;
}
什么是
BoardListener
?BoardListener是类名,我没有注意到当我将类名更改为ClipBoardListener时,有这个类的实例。它应该是公共类BoardListener。对不起,我的错误…..它给出了一些例外:“未能初始化与ProtocolHandler[“http-apr-80”]关联的端点”。此技术会干扰某些Linux文件管理器。复制文件时,程序将“接管”剪贴板,您无法粘贴该文件。有人知道为什么吗?我还没有尝试在Windows上复制文件。Linux的另一个问题是,如果剪贴板所有者(程序)关闭,剪贴板将被擦除。这是违反直觉的,因为您没有关闭复制内容的程序。Windows不会受到这种影响。我不确定这是否真的适用于我:从我的实验来看,当(例如)我第一次选择并复制一些文本时,侦听器似乎会做出响应。。。但是如果我再复制一些文本,听者就不会激发。这不是
Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(new FlavorListener() {
@Override
public void flavorsChanged(FlavorEvent e) {
System.out.println("ClipBoard UPDATED: " + e.getSource() + " " + e.toString());
}
});
public class ClipBoardListener extends Thread implements ClipboardOwner{
Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard();
@Override
public void run() {
Transferable trans = sysClip.getContents(this);
TakeOwnership(trans);
}
@Override
public void lostOwnership(Clipboard c, Transferable t) {
try {
ClipBoardListener.sleep(250); //waiting e.g for loading huge elements like word's etc.
} catch(Exception e) {
System.out.println("Exception: " + e);
}
Transferable contents = sysClip.getContents(this);
try {
process_clipboard(contents, c);
} catch (Exception ex) {
Logger.getLogger(ClipBoardListener.class.getName()).log(Level.SEVERE, null, ex);
}
TakeOwnership(contents);
}
void TakeOwnership(Transferable t) {
sysClip.setContents(t, this);
}
public void process_clipboard(Transferable t, Clipboard c) { //your implementation
String tempText;
Transferable trans = t;
try {
if (trans != null?trans.isDataFlavorSupported(DataFlavor.stringFlavor):false) {
tempText = (String) trans.getTransferData(DataFlavor.stringFlavor);
System.out.println(tempText);
}
} catch (Exception e) {
}
}
}
public class ClipboardListenerTest {
public static void main(String[] args) throws InvocationTargetException, InterruptedException {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.addFlavorListener(new FlavorListener() {
// this is needed to prevent output when you clear the clipboard
boolean suppressOutput = false;
// this is a specially devised Transferable - sole purpose to clear the clipboard
Transferable clearingTransferable = new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[0];
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return false;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
throw new UnsupportedFlavorException(flavor);
}
};
@Override
public void flavorsChanged(FlavorEvent e) {
Transferable contentsTransferable = clipboard.getContents(null);
// NB the Transferable returned from getContents is NEVER the same as the
// clearing Transferable!
if (!suppressOutput) {
System.out.println(String.format("# clipboard UPDATED, src %s, string %s, clearingT? %b", e.getSource(), e.toString(),
contentsTransferable == clearingTransferable));
try {
String stringData = (String)clipboard.getData(DataFlavor.stringFlavor);
System.out.println(String.format("# string data |%s|", stringData ));
} catch (UnsupportedFlavorException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else {
// my experiments seem to show that you have to spawn a new Runnable if you want
// to leave suppressOutput long enough for it to prevent the "CLEAR" operation
// producing output...
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
suppressOutput = false;
}
});
}
suppressOutput = true;
clipboard.setContents(clearingTransferable, null);
}
});
}
});
int i = 0;
while (i < 100) {
Thread.sleep(500L);
System.out.println("# pibble");
i++;
}
}
}
final Clipboard SYSTEM_CLIPBOARD = Toolkit.getDefaultToolkit().getSystemClipboard();
SYSTEM_CLIPBOARD.addFlavorListener(listener -> {
string clipboardText = (String) SYSTEM_CLIPBOARD.getData(DataFlavor.stringFlavor);
SYSTEM_CLIPBOARD.setContents(new StringSelection(clipboardText), null);
System.out.println("The clipboard contains: " + clipboardText);
}
public static class ClipboardHandler implements ClipboardOwner, Runnable {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
private final Consumer<String> bufferConsumer;
public ClipboardHandler(Consumer<String> bufferConsumer) {
this.bufferConsumer = bufferConsumer;
}
@Override
public void lostOwnership(Clipboard clipboard, Transferable notUsed) {
Transferable contents = clipboard.getContents(this);
if (contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
String string = (String) contents.getTransferData(DataFlavor.stringFlavor);
bufferConsumer.accept(string);
} catch (Exception e) {
logger.error("Unable to read clipboard buffer.", e);
}
}
getOwnership(contents);
}
@Override
public void run() {
Transferable transferable = clipboard.getContents(this);
getOwnership(transferable);
}
public void setBuffer(String buffer) {
getOwnership(new StringSelection(buffer));
}
private void getOwnership(Transferable transferable) {
clipboard.setContents(transferable, this);
}
}
public static void main(String[] args) {
ClipboardHandler clipboardHandler = new ClipboardHandler(System.out::println);
EventQueue.invokeLater(clipboardHandler);
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String buffer = scanner.nextLine();
if (!buffer.trim().isEmpty()) {
clipboardHandler.setBuffer(buffer);
}
}
}
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
public class ClipboardWatcher {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame(ClipboardWatcher.class.getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextPane tp = new JTextPane();
tp.setPreferredSize(new Dimension(384, 256));
f.getContentPane().add(new JScrollPane(tp));
f.pack();
f.setVisible(true);
new Timer(200, e -> {
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
DataFlavor df = DataFlavor.stringFlavor;
if (c.isDataFlavorAvailable(df)) {
try {
String data = c.getData(df).toString();
if (!data.equals(_lastData))
tp.setText(_lastData = data);
} catch (Exception ex) {
System.err.println(ex);
}
}
}).start();
});
}
private static String _lastData;
}