Frank
Frank

Reputation: 31090

How to get systemclipboard image after copying some text in Java?

I'm testing a Swing App, it uses robot to do a Alt+ScreenPrint to get the current window's image, but if I copy some text into systemclipboard first, then it won't get the image properly, as seen below, if I click on the "Test" button, it gets the image and output the following :

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

The "Test_Image" point to a BufferedImage, and you can paste it into a MS Paint program.

But if I click on the "Copy & Test" button, it will copy some text on to the clipboard, then copy the image on to the clipboard, but then it can't get to the image, the output looks like this :

Get_Clipboard_Image : [In Test_Clip_Board] transferable = sun.awt.datatransfer.TransferableProxy@5d1432f7
 Test_Image = null

As you can see, somehow the transferable becomes a "TransferableProxy" instead of "ClipboardTransferable" which holds an image, and the "Test_Image = null".

But the strange thing is : the image IS IN THE systemclipboard, you can try to paste it in a MS Paint, and see it does exist, but at this time Java just can't get to it, because of the "TransferableProxy".

I do need to copy text into the clipboard first then copy image on to the clipboard, so how to fix this ?

Here is my app :

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(); } });
  }
}

Upvotes: 0

Views: 151

Answers (1)

SubOptimal
SubOptimal

Reputation: 22983

The PrintScreen event is not yet processed by the AWT-EventQueue when you execute the code in the ActionListener.

If you amend your code as

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);
        }
    });
}

the image will be read from the clipboard, as the runnable from the invocation of SwingUtilities.invokeLater will be executed after the code of the ActionLister from the button is finished.

The AWT event queue will process the events in that order

  • action handler from the button, which will block other AWT events to run at the same time
  • the prinscreen will be enqueued
  • the invoke later runnable will be enqueued

Adding a FlavorListener to the clipboard seems to be a better solution.

Upvotes: 2

Related Questions