我想从屏幕上捕获图像并在JPanel中绘制它,它工作,但它再次显示一次,就像进入循环一样,我对此感到困惑,我该如何修复它,请?变量Iwidth, iheight在上面初始化了,但是我取了导致问题的代码块
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Image img;
ImageIcon i = null;
Rectangle screenRect=new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
BufferedImage capture=new Robot().createScreenCapture(screenRect);
capture.getHeight();
capture.getWidth();
i=new ImageIcon(capture);
} catch (AWTException ex) {
Logger.getLogger(TestDrawing.class.getName()).log(Level.SEVERE, null, ex);
}
img = i.getImage();
g.drawImage(img,Iwidth,Ihieght,null);
super.repaint();
}
永远不要在paintComponent中使用这样的代码。该方法应该只用于绘制和绘制,并且是一个您无法完全控制的方法,因为它是由JVM调用的,以响应您的请求和来自操作系统的请求,即使您请求重新绘制,也不能保证它将被遵守,特别是当请求堆积时。此外,GUI的感知响应性通常取决于绘制完成的速度,而文件读取和图像捕获永远不应该在paintComponent中完成。
相反,您应该读取图像作为对某些事件的反应,可能是计时器,然后在读取图像后,调用repaint()
并在paintComponent中绘制获得的图像。
也不要在paintComponent内部调用repaint()
。
类似于伪代码
// inside of the ActionListener of a Swing Timer (if you want to do this repeatedly)
get screen image from robot and feed it into the capture BufferedImage field
consider doing this in a SwingWorker
call repaint() when SwingWorker is done (via a PropertyChangeListener)
Inside of paintComponent:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (capture != null) {
g.drawImage(capture, capture.getWidth(), capture.getHeight());
}
}
编辑
例如:import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.SwingWorker.StateValue;
public class ScreenCaptureTest extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private JButton btn = new JButton(new ScreenCaptureAction(this,
"Capture Screen", KeyEvent.VK_C));
private ImagePanel imagePanel = new ImagePanel();
public ScreenCaptureTest() {
JPanel buttonPanel = new JPanel();
buttonPanel.add(btn);
setLayout(new BorderLayout());
add(new JScrollPane(imagePanel), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
}
public void setImagePanelImage(BufferedImage img) {
imagePanel.setImage(img);
revalidate();
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ScreenCaptureTest mainPanel = new ScreenCaptureTest();
JFrame frame = new JFrame("ScreenCaptureTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ImagePanel extends JPanel {
private BufferedImage image;
public void setImage(BufferedImage image) {
this.image = image;
revalidate();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
@Override
public Dimension getPreferredSize() {
if (image != null) {
return new Dimension(image.getWidth(), image.getHeight());
}
return super.getPreferredSize();
}
}
class ScreenCaptureAction extends AbstractAction {
private ScreenCaptureTest screenCaptureTest;
public ScreenCaptureAction(ScreenCaptureTest screenCaptureTest, String name,
int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
this.screenCaptureTest = screenCaptureTest;
}
@Override
public void actionPerformed(ActionEvent e) {
setEnabled(false);
final SwingWorker<BufferedImage, Void> mySwingWorker = new SwingWorker<BufferedImage, Void>() {
@Override
protected BufferedImage doInBackground() throws Exception {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
Robot robot = new Robot();
BufferedImage capture = robot.createScreenCapture(new Rectangle(
screenSize));
return capture;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if ("state".equals(pcEvt.getPropertyName())
&& pcEvt.getNewValue() == StateValue.DONE) {
setEnabled(true);
try {
screenCaptureTest.setImagePanelImage(mySwingWorker.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
}
}
编辑
注意,如果这是我的程序,我会在JLabel中将图像显示为ImageIcon,因为这样编写代码要简单得多。然后你可以去掉ImagePanel类和它的paintComponent方法,并简单地将main代码为:
public class ScreenCaptureTest extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private JButton btn = new JButton(new ScreenCaptureAction(this,
"Capture Screen", KeyEvent.VK_C));
//!! private ImagePanel imagePanel = new ImagePanel();
private JLabel screenLabel = new JLabel(); //!!
public ScreenCaptureTest() {
JPanel buttonPanel = new JPanel();
buttonPanel.add(btn);
setLayout(new BorderLayout());
//!! add(new JScrollPane(imagePanel), BorderLayout.CENTER);
add(new JScrollPane(screenLabel), BorderLayout.CENTER); //!!
add(buttonPanel, BorderLayout.SOUTH);
}
public void setImagePanelImage(BufferedImage img) {
//!! imagePanel.setImage(img);
Icon icon = new ImageIcon(img);
screenLabel.setIcon(icon);
//!! revalidate();
//!! repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ScreenCaptureTest mainPanel = new ScreenCaptureTest();
JFrame frame = new JFrame("ScreenCaptureTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}