如何在复制 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 添加到剪贴板似乎是更好的解决方案。