Screenshots erstellen -> Effinzient

Ich arbeite gerade an meinen Swing Framework und schreibe gerade eine Action, die einen Screenshot des Fensters erstellt und dieses dann speichert. Nur wenn ich das Menü Item anklicke dass die Action ausloest, dann ist im Foto immer eben dieses Menü drauf, was eig nicht sein sollte. Habt ihr ne Idee wie ich das verhindern kann? Habe ein Thread.sleep(200) benutzt, ist aber meiner Meinung nach verdammt unsauber…

package de.framework.actions;

import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.SwingWorker;

import de.framework.Application;
import de.framework.BasicApplicationAction;

@SuppressWarnings("serial")
class SnapshotAction extends BasicApplicationAction {

// TODO: Use i18n!
public SnapshotAction(Application application) {
super("Create snapshot...", application);
}

@Override
public void actionPerformed(ActionEvent e) {
new SnapshotWorker().execute();
}

private class SnapshotWorker extends SwingWorker<BufferedImage, Object> {

@Override
protected BufferedImage doInBackground() throws Exception {
// TODO: Find another cleaner way...
Thread.sleep(200);
JFrame frame = getApplication().getView().getMainFrame();
Robot robot = new Robot();
return robot.createScreenCapture(frame.getBounds());
}

@Override
protected void done() {
try {
BufferedImage image = get();
if (image != null) {
File save = getSavingFile();
if (save != null) {
// TODO: Let the user/dev choose
ImageIO.write(image, "png", save);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

private File getSavingFile() {
JFileChooser fc = new JFileChooser();
int retVal = fc.showSaveDialog(null);
if (retVal == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile();
}
return null;
}
}

Wenn es wirklich ein Screenshot sein soll, würde mir da spontan nichts nicht-frickeliges einfallen - und nichts, was verhindern würde, dass der Screeshot z.B. auch Teile eines anderen Fensters enthält, das das eigentliche Fenster überdeckt. Je nachdem, was das werden soll… ein Robot ist etwas speziell, eigentlich nur für Tests gedacht, und und selten für “normale” Entwicklung. Vielleicht wäre eine Alternative, ein BufferedImage zu erstellen, und in dessen Graphics dann den Frame reinzupainten, mit
frame.print(buGraphics);
?!

Hm davonn wusstr ich jetzt nichts, ist aber einen Versuch wert. danke :smiley:

Ich würde auch zu Marcos Idee raten. Abgesehen von dem Vorteil, dass nichts überdeckt werden kann, kannst du natürlich selber Einfluss auf den Screenshot nehmen. So ist es z.B. sehr einfach noch ein Wasserzeichen in das Bild zu schreiben:

{
    public static void main(String[] args) {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JButton button = new JButton("Hallo Welt");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_ARGB);
                Graphics graphics = image.createGraphics();
                frame.paint(graphics); // Screenshot zeichnen
                graphics.setColor(Color.BLACK); 
                graphics.drawString("(c) MyCompany 2013", 10, 10); // Copyright zeichnen
                graphics.dispose();

                try {
                    ImageIO.write(image, "png", new File("[pfad]/test.png"));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        });
        frame.add(button);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.setVisible(true);
            }
        });
    }
}```

Ok das ist echt cool :smiley: