0

I want to take a print screen of what is behind the JFrame, without the JFrame itself. The way I tried was to close the window, wait for a while so it fully closes, then take the print screen and then open it again. The current method is not good for what I need since I need to do it more frequently and waiting for the window to close is too much time. Also, I don't want to close the window for that.

Here is my current code:

public class Offscreen {

    private static BufferedImage img;

    public static void main(String[] main)
                throws AWTException, InterruptedException {
        JFrame frame = new JFrame() {
            @Override
            public void paint(Graphics g) {
                if (img != null)
                    // draw print screen
                    g.drawImage(img, 0, 0, null);
            }
        };
        frame.setSize(500, 500);
        frame.setLocation(700, 0);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        frame.setVisible(false);

        Thread.sleep(200);

        // take the picture
        Robot r = new Robot();
        img = r.createScreenCapture(frame.getBounds());

        // show the source again
        frame.setVisible(true);
        // print on destiny
        frame.repaint();
    }
}
NX1125
  • 103
  • 1
  • 3
  • 6
  • 2
    You want to do what? Is it me, or are others also having a tough time deciphering just what it is that you're trying to do? – Hovercraft Full Of Eels Oct 11 '14 at 21:54
  • He has as frame that shows the printscreen he takes, the problem is the frame is visible in the printscreen, I am guessing he wants the printscreen first and then once that is available, to show it on a frame. – arynaq Oct 11 '14 at 21:58

1 Answers1

2

"Assuming" you only want to capture the area behind the active frame (and as you say, without the frame), then something like..

import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PrintScreen01 {

    public static void main(String[] args) {
        new PrintScreen01();
    }

    private Timer timer;

    public PrintScreen01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                final PrintPane printPane = new PrintPane();

                final JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(printPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.addComponentListener(new ComponentAdapter() {

                    @Override
                    public void componentMoved(ComponentEvent e) {
                        timer.restart();
                    }

                    @Override
                    public void componentResized(ComponentEvent e) {
                        timer.restart();
                    }

                });
                timer = new Timer(250, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (frame.isVisible()) {
                            takeSnapShot(frame, printPane);
                        }
                    }
                });
                timer.setRepeats(false);
                frame.setVisible(true);
//                takeSnapShot(frame, printPane);
            }
        });
    }

    public void takeSnapShot(JFrame frame, PrintPane pane) {

        Rectangle bounds = new Rectangle(pane.getLocationOnScreen(), pane.getSize());
        frame.setVisible(false);
        new SnapShotWorker(frame, pane, bounds).execute();

    }

    public class SnapShotWorker extends SwingWorker<BufferedImage, BufferedImage> {

        private JFrame frame;
        private PrintPane pane;
        private Rectangle captureBounds;

        public SnapShotWorker(JFrame frame, PrintPane pane, Rectangle bounds) {
            this.frame = frame;
            this.pane = pane;
            captureBounds = bounds;
        }

        @Override
        protected BufferedImage doInBackground() throws Exception {

            Thread.sleep(125);

            BufferedImage snapShot = null;
            try {
                Robot bot = new Robot();
                snapShot = bot.createScreenCapture(captureBounds);
            } catch (AWTException ex) {
                ex.printStackTrace();
            }
            Thread.sleep(125);
            return snapShot;
        }

        @Override
        protected void done() {
            try {
                BufferedImage snapShot = get();
                pane.setSnapShot(snapShot);
                frame.setVisible(true);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (ExecutionException ex) {
                ex.printStackTrace();
            }
        }



    }

    public class PrintPane extends JPanel {

        private BufferedImage background;

        public PrintPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public void setSnapShot(BufferedImage img) {
            background = img;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
                g2d.drawImage(background, 0, 0, this);
                g2d.dispose();
            }
        }

    }

}

May help...

Now, I had some issues with the timing of Robot, it would seem that part of the operation is threaded in some way, meaning that unless you got the timing of the frame changing between invisible and visible "just" right, you would actually recapture the frame...annoying...

To try and fix this, and reduce the amount of times I tried capturing the screen, I employed a javax.swing.Timer (to reduce the capture attempts) and a SwingWorker to control the actual snapshot process, taking it out of the Event Dispatching Thread, there by ensuring (to some degree) that the window will be invisible.

I also added some additional lag to ensure that the frame was off the screen long enough to prevent it been capture by the snapshot...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Help a lot, but the user will see the frame hiding and opening. But thanks anyway. – NX1125 Oct 11 '14 at 22:44
  • There's no way around it, if you don't want the frame on the screen, then you will need to hide it first, you can't "capture" underneath an active window – MadProgrammer Oct 12 '14 at 01:41
  • [This example](http://stackoverflow.com/questions/13948122/drawing-a-bounding-rectangle-to-select-what-area-to-record/13948198#13948198) is kind of cheat... – MadProgrammer Oct 12 '14 at 01:43
  • There is no how to disable robot capture some frames? Like take the under layers? Or take what have been painted on a translucent frame like the background? – NX1125 Oct 12 '14 at 01:50
  • Remember, what you are seeing on the screen is nothing more than a bitmap, the "layers" or virtualized only, so it's not possible to have `Robot` capture anything other than what's active on the screen, as the functionality is depended on the underlying OS anyway. Without known exactly what is you hope to achieve, it's hard to make a suggestion. What I have done in the past in captured the entire desktop and painted it to a very large, borderless, window and "faked" the selection from there – MadProgrammer Oct 12 '14 at 01:54
  • [This is another example](http://stackoverflow.com/questions/18158550/zoom-box-for-area-around-mouse-location-on-screen/18158845#18158845) were we capture a small section of the screen, zoom it and display it within a popup... – MadProgrammer Oct 12 '14 at 01:56
  • The mouse pointer "hides" in capture, can do the same for JFrame? – NX1125 Oct 12 '14 at 02:17
  • Yes, but this controlled by the OS, it's beyond the capabilities of what Java provides – MadProgrammer Oct 12 '14 at 02:59
  • I will use your code, but the frame appears in print screen when closes, it must increase the delay... – NX1125 Oct 12 '14 at 14:35