如何在复制 Java 中的一些文本后获取系统剪贴板图像?
How to get systemclipboard image after copying some text in Java?
我正在测试一个 Swing 应用程序,它使用机器人执行 Alt+ScreenPrint 来获取当前 window 的图像,但是如果我先将一些文本复制到系统剪贴板,那么它不会正确获取图像,如下所示,如果我单击 "Test" 按钮,它会获取图像并输出以下内容:
Get_Clipboard_Image : [In Test_Clip_Board] transferable = sun.awt.datatransfer.ClipboardTransferable@26acefbf
Get_Clipboard_Image : [In Test_Clip_Board] BufferedImage@505497f7: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 816 height = 664 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
Test_Image = BufferedImage@505497f7: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 816 height = 664 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
"Test_Image" 指向 BufferedImage,您可以将其粘贴到 MS 画图程序中。
但是如果我点击 "Copy & Test" 按钮,它会将一些文本复制到剪贴板,然后将图像复制到剪贴板,但是它无法获取图像,输出看起来像这样:
Get_Clipboard_Image : [In Test_Clip_Board] transferable = sun.awt.datatransfer.TransferableProxy@5d1432f7
Test_Image = null
如您所见,可转让文件以某种方式变成了 "TransferableProxy" 而不是 "ClipboardTransferable" ,而 "Test_Image = null".
但奇怪的是:图像在系统剪贴板中,您可以尝试将其粘贴到 MS Paint 中,看到它确实存在,但此时 Java 就是无法获取它,因为 "TransferableProxy".
我确实需要先将文本复制到剪贴板,然后再将图像复制到剪贴板,那么如何解决这个问题?
这是我的应用程序:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test_Clip_Board extends JPanel
{
public static final long serialVersionUID=26362862L;
static Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
static JFrame frame=new JFrame("Test_Clip_Board");
int W=800,H=626,Upper_Left_Button_Panel_W=90;
String Current_Path=new File("").getAbsolutePath().replace("\","/")+"/";
static Insets An_Inset=new Insets(0,0,0,0);
JTextArea TextArea=new JTextArea("Test Clip Board");
Robot robot;
Point Location;
public Test_Clip_Board()
{
TextArea.append("\n\nCurrent_Path = "+Current_Path);
try { robot=new Robot(); }
catch (Exception e) { e.printStackTrace(); }
FlowLayout Fl=new FlowLayout(0,0,0);
setLayout(Fl);
JPanel leftPanel=new JPanel(Fl);
leftPanel.setBorder(new EtchedBorder());
leftPanel.setPreferredSize(new Dimension(W/2,H));
add(leftPanel);
JPanel upperPanel=new JPanel(Fl);
upperPanel.setBorder(new EtchedBorder());
upperPanel.setPreferredSize(new Dimension(W/2-2,H/4-2));
leftPanel.add(upperPanel);
TextArea.setFont(new Font("Times New Roman",0,18));
TextArea.setBorder(new EtchedBorder());
TextArea.setPreferredSize(new Dimension(W/2-2-Upper_Left_Button_Panel_W-4,H/4-6));
upperPanel.add(TextArea);
JPanel buttonPanel=new JPanel(new FlowLayout(0,0,30));
buttonPanel.setBorder(new EtchedBorder());
buttonPanel.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W,H/4-6));
upperPanel.add(buttonPanel);
JButton testButton=new JButton("Test");
testButton.setForeground(new Color(0,0,230));
testButton.setFont(new Font("Times New Roman",0,16));
testButton.setMargin(An_Inset);
testButton.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W-5,26));
testButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Test(); } });
buttonPanel.add(testButton);
JButton copyAndTestButton=new JButton("Copy & Test");
copyAndTestButton.setForeground(new Color(0,0,230));
copyAndTestButton.setFont(new Font("Times New Roman",0,13));
copyAndTestButton.setMargin(An_Inset);
copyAndTestButton.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W-5,26));
copyAndTestButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Copy_And_Test(); } });
buttonPanel.add(copyAndTestButton);
setPreferredSize(new Dimension(W,H));
}
void Do_Copy_And_Test()
{
Clipboard system=Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection sel=new StringSelection(TextArea.getText());
system.setContents(sel,sel);
Do_Test();
}
void Do_Test()
{
Point TeatArea_Location=TextArea.getLocationOnScreen();
Robot_Do_Alt_PrintScreen(20,TeatArea_Location.x+30,TeatArea_Location.y+30,20);
Image Test_Image=Get_Clipboard_Image("In Test_Clip_Board");
Out(" Test_Image = "+Test_Image);
}
Image Get_Clipboard_Image(String Text)
{
Image image=null;
Transferable transferable=Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
try
{
Out("Get_Clipboard_Image : ["+Text+"] transferable = "+transferable.toString());
if (transferable!=null && transferable.isDataFlavorSupported(DataFlavor.imageFlavor))
{
image=(Image)transferable.getTransferData(DataFlavor.imageFlavor); // getting image from Clipboard
Out("Get_Clipboard_Image : ["+Text+"] "+image);
}
}
catch (UnsupportedFlavorException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
return image;
}
void Robot_Do_Alt_PrintScreen(int Delay_Before_Click,int X,int Y,int Delay_After_Click)
{
robot.delay(Delay_Before_Click);
robot.mouseMove(X,Y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(20);
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(KeyEvent.VK_PRINTSCREEN);
robot.keyRelease(KeyEvent.VK_PRINTSCREEN);
robot.keyRelease(KeyEvent.VK_ALT);
// if (Is_Test) Out("Robot_Click : [ X = "+X+" Y = "+Y+" ]");
robot.delay(Delay_After_Click);
}
private static void out(String message) { System.out.print(message); }
private static void Out(String message) { System.out.println(message); }
// Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
static void Create_And_Show_GUI()
{
final Test_Clip_Board demo=new Test_Clip_Board();
frame.add(demo);
frame.addWindowListener( new WindowAdapter()
{
public void windowActivated(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowClosing(WindowEvent e) { System.exit(0); }
public void windowDeactivated(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { demo.repaint(); }
public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
public void windowIconified(WindowEvent e) { }
public void windowLostFocus(WindowEvent e) { }
public void windowOpening(WindowEvent e) { demo.repaint(); }
public void windowOpened(WindowEvent e) { }
public void windowResized(WindowEvent e) { demo.repaint(); }
public void windowStateChanged(WindowEvent e) { demo.repaint(); }
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args)
{
// Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
}
}
当您执行 ActionListener
中的代码时,PrintScreen
事件尚未被 AWT-EventQueue
处理。
如果您将代码修改为
void Do_Test() {
Point TeatArea_Location = TextArea.getLocationOnScreen();
Robot_Do_Alt_PrintScreen(20, TeatArea_Location.x + 30, TeatArea_Location.y + 30, 20);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Image Test_Image = Get_Clipboard_Image("In Test_Clip_Board");
Out(" Test_Image = " + Test_Image);
}
});
}
图像将从剪贴板中读取,因为来自 SwingUtilities.invokeLater
的调用的 运行nable 将在按钮的 ActionLister
代码完成后执行。
AWT 事件队列将按该顺序处理事件
- 来自按钮的操作处理程序,它将同时阻止其他 AWT 事件到 运行
- prinscreen 将入队
- 稍后的调用运行nable 将入队
将 FlavorListener
添加到剪贴板似乎是更好的解决方案。
我正在测试一个 Swing 应用程序,它使用机器人执行 Alt+ScreenPrint 来获取当前 window 的图像,但是如果我先将一些文本复制到系统剪贴板,那么它不会正确获取图像,如下所示,如果我单击 "Test" 按钮,它会获取图像并输出以下内容:
Get_Clipboard_Image : [In Test_Clip_Board] transferable = sun.awt.datatransfer.ClipboardTransferable@26acefbf
Get_Clipboard_Image : [In Test_Clip_Board] BufferedImage@505497f7: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 816 height = 664 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
Test_Image = BufferedImage@505497f7: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 816 height = 664 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
"Test_Image" 指向 BufferedImage,您可以将其粘贴到 MS 画图程序中。
但是如果我点击 "Copy & Test" 按钮,它会将一些文本复制到剪贴板,然后将图像复制到剪贴板,但是它无法获取图像,输出看起来像这样:
Get_Clipboard_Image : [In Test_Clip_Board] transferable = sun.awt.datatransfer.TransferableProxy@5d1432f7
Test_Image = null
如您所见,可转让文件以某种方式变成了 "TransferableProxy" 而不是 "ClipboardTransferable" ,而 "Test_Image = null".
但奇怪的是:图像在系统剪贴板中,您可以尝试将其粘贴到 MS Paint 中,看到它确实存在,但此时 Java 就是无法获取它,因为 "TransferableProxy".
我确实需要先将文本复制到剪贴板,然后再将图像复制到剪贴板,那么如何解决这个问题?
这是我的应用程序:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test_Clip_Board extends JPanel
{
public static final long serialVersionUID=26362862L;
static Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
static JFrame frame=new JFrame("Test_Clip_Board");
int W=800,H=626,Upper_Left_Button_Panel_W=90;
String Current_Path=new File("").getAbsolutePath().replace("\","/")+"/";
static Insets An_Inset=new Insets(0,0,0,0);
JTextArea TextArea=new JTextArea("Test Clip Board");
Robot robot;
Point Location;
public Test_Clip_Board()
{
TextArea.append("\n\nCurrent_Path = "+Current_Path);
try { robot=new Robot(); }
catch (Exception e) { e.printStackTrace(); }
FlowLayout Fl=new FlowLayout(0,0,0);
setLayout(Fl);
JPanel leftPanel=new JPanel(Fl);
leftPanel.setBorder(new EtchedBorder());
leftPanel.setPreferredSize(new Dimension(W/2,H));
add(leftPanel);
JPanel upperPanel=new JPanel(Fl);
upperPanel.setBorder(new EtchedBorder());
upperPanel.setPreferredSize(new Dimension(W/2-2,H/4-2));
leftPanel.add(upperPanel);
TextArea.setFont(new Font("Times New Roman",0,18));
TextArea.setBorder(new EtchedBorder());
TextArea.setPreferredSize(new Dimension(W/2-2-Upper_Left_Button_Panel_W-4,H/4-6));
upperPanel.add(TextArea);
JPanel buttonPanel=new JPanel(new FlowLayout(0,0,30));
buttonPanel.setBorder(new EtchedBorder());
buttonPanel.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W,H/4-6));
upperPanel.add(buttonPanel);
JButton testButton=new JButton("Test");
testButton.setForeground(new Color(0,0,230));
testButton.setFont(new Font("Times New Roman",0,16));
testButton.setMargin(An_Inset);
testButton.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W-5,26));
testButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Test(); } });
buttonPanel.add(testButton);
JButton copyAndTestButton=new JButton("Copy & Test");
copyAndTestButton.setForeground(new Color(0,0,230));
copyAndTestButton.setFont(new Font("Times New Roman",0,13));
copyAndTestButton.setMargin(An_Inset);
copyAndTestButton.setPreferredSize(new Dimension(Upper_Left_Button_Panel_W-5,26));
copyAndTestButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Copy_And_Test(); } });
buttonPanel.add(copyAndTestButton);
setPreferredSize(new Dimension(W,H));
}
void Do_Copy_And_Test()
{
Clipboard system=Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection sel=new StringSelection(TextArea.getText());
system.setContents(sel,sel);
Do_Test();
}
void Do_Test()
{
Point TeatArea_Location=TextArea.getLocationOnScreen();
Robot_Do_Alt_PrintScreen(20,TeatArea_Location.x+30,TeatArea_Location.y+30,20);
Image Test_Image=Get_Clipboard_Image("In Test_Clip_Board");
Out(" Test_Image = "+Test_Image);
}
Image Get_Clipboard_Image(String Text)
{
Image image=null;
Transferable transferable=Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
try
{
Out("Get_Clipboard_Image : ["+Text+"] transferable = "+transferable.toString());
if (transferable!=null && transferable.isDataFlavorSupported(DataFlavor.imageFlavor))
{
image=(Image)transferable.getTransferData(DataFlavor.imageFlavor); // getting image from Clipboard
Out("Get_Clipboard_Image : ["+Text+"] "+image);
}
}
catch (UnsupportedFlavorException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
return image;
}
void Robot_Do_Alt_PrintScreen(int Delay_Before_Click,int X,int Y,int Delay_After_Click)
{
robot.delay(Delay_Before_Click);
robot.mouseMove(X,Y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(20);
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(KeyEvent.VK_PRINTSCREEN);
robot.keyRelease(KeyEvent.VK_PRINTSCREEN);
robot.keyRelease(KeyEvent.VK_ALT);
// if (Is_Test) Out("Robot_Click : [ X = "+X+" Y = "+Y+" ]");
robot.delay(Delay_After_Click);
}
private static void out(String message) { System.out.print(message); }
private static void Out(String message) { System.out.println(message); }
// Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
static void Create_And_Show_GUI()
{
final Test_Clip_Board demo=new Test_Clip_Board();
frame.add(demo);
frame.addWindowListener( new WindowAdapter()
{
public void windowActivated(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowClosing(WindowEvent e) { System.exit(0); }
public void windowDeactivated(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { demo.repaint(); }
public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
public void windowIconified(WindowEvent e) { }
public void windowLostFocus(WindowEvent e) { }
public void windowOpening(WindowEvent e) { demo.repaint(); }
public void windowOpened(WindowEvent e) { }
public void windowResized(WindowEvent e) { demo.repaint(); }
public void windowStateChanged(WindowEvent e) { demo.repaint(); }
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args)
{
// Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
}
}
当您执行 ActionListener
中的代码时,PrintScreen
事件尚未被 AWT-EventQueue
处理。
如果您将代码修改为
void Do_Test() {
Point TeatArea_Location = TextArea.getLocationOnScreen();
Robot_Do_Alt_PrintScreen(20, TeatArea_Location.x + 30, TeatArea_Location.y + 30, 20);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Image Test_Image = Get_Clipboard_Image("In Test_Clip_Board");
Out(" Test_Image = " + Test_Image);
}
});
}
图像将从剪贴板中读取,因为来自 SwingUtilities.invokeLater
的调用的 运行nable 将在按钮的 ActionLister
代码完成后执行。
AWT 事件队列将按该顺序处理事件
- 来自按钮的操作处理程序,它将同时阻止其他 AWT 事件到 运行
- prinscreen 将入队
- 稍后的调用运行nable 将入队
将 FlavorListener
添加到剪贴板似乎是更好的解决方案。