1

我正在尝试创建一个读取屏幕并将其显示在帧中的线程,此代码旨在以 5fps 运行,到目前为止它读取屏幕,但我无法让 JFrame 显示每个“帧”的更新图像或 200 毫秒。当我使用重绘()时;或重新验证();

public static void startScreenRecorder() 
{
    Thread screenThread = new Thread()
    {
        public synchronized void run()
        {
            long time;
            long lastFrameTime = 0;
            JFrame frame = new JFrame("Screen capture");
            ImagePanel panel = new ImagePanel(captureScreen());
            frame.add(panel);
            frame.setSize(300, 400);
            frame.setVisible(true);

            while (true) 
            {
                time = System.currentTimeMillis();
                while (time - lastFrameTime < 190) 
                {
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                    }

                    time = System.currentTimeMillis();
                }                
                lastFrameTime = time;

                panel = new ImagePanel(captureScreen());
                panel.revalidate();
                panel.repaint();
                frame.revalidate();
                frame.repaint();
            }
        }
    };
    screenThread.start();
}
4

2 回答 2

2

不要使用 Thread.sleep() 来尝试控制动画。

动画应该使用Swing Timer来完成。当您使用计时器时,EDT 上的 GUI 会自动更新。

panel = new ImagePanel(captureScreen());

上面的代码没有做任何事情。它只是在内存中创建一个面板。您实际上无处将面板添加到 GUI。更改变量的引用不会更新 GUI。

相反,您可能应该将 JLabel 添加到框架(当您最初创建框架时)。然后,当您有一个新图像时,您只需执行以下操作:

label.setIcon( new ImageIcon( your screen capture ) );
于 2013-04-19T04:19:37.890 回答
1

如果您的代码根本没有显示任何图像,我不会感到惊讶,因为它忽略了 Swing 线程规则:

  • 所有 Swing 代码只需要在 Swing 事件调度线程 (EDT) 上调用。
  • 所有其他长时间运行的代码都需要在后台线程中调用。我认为这意味着captureScreen().
  • Thread.sleep(...)除非您想让整个应用程序进入睡眠状态,否则您永远不应该调用Swing 事件线程。
  • 也许最好使用摆动计时器。
  • 您创建了新的 ImagePanel,但对它们什么也不做——例如,除了第一个 JPanel 之外,您从不将它们添加到 GUI 中。请注意,如果您更改变量引用的对象,此处为面板变量,这将绝对不会影响在其他地方使用的对象实例,即在 GUI 中显示的 JPanel。
  • 与其创建新的 JPanel,不如用您的图像创建 ImageIcons 并将可视化的 JLabel 的图标替换为setIcon(...)?
  • 由于您有很多背景资料,请考虑使用 aSwingWorker<Void, Icon>来完成您的工作,并让它发布 ImageIcon,然后将其显示在 GUI 的 JLabel 中。如果你这样做了,那么你可能不会使用 Swing Timer,因为计时将在 SwingWorker 的后台线程中完成。

例如:

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

@SuppressWarnings("serial")
public class SwingWorkerEg extends JPanel {
   private static final int PREF_W = 600;
   private static final int PREF_H = 400;
   private JLabel displayedLabel = new JLabel();

   public SwingWorkerEg() {
      setLayout(new BorderLayout());
      add(displayedLabel);
      try {
         MySwingWorker mySwingWorker = new MySwingWorker();
         mySwingWorker.execute();
      } catch (AWTException e) {
         e.printStackTrace();
      }
   }

   public void setLabelIcon(Icon icon) {
      displayedLabel.setIcon(icon);
   }

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

   private class MySwingWorker extends SwingWorker<Void, Icon> {
      private final Rectangle SCREEN_RECT = new Rectangle(0, 0, PREF_W,
            PREF_H);
      private Robot robot = null;

      public MySwingWorker() throws AWTException {
         robot = new Robot();
      }

      @Override
      protected Void doInBackground() throws Exception {
         Timer utilTimer = new Timer();
         TimerTask task = new TimerTask() {

            @Override
            public void run() {
               BufferedImage capturedImage = captureScreen();
               publish(new ImageIcon(capturedImage));
            }

         };
         long delay = 200;
         utilTimer.scheduleAtFixedRate(task, delay, delay);
         return null;
      }

      @Override
      protected void process(List<Icon> chunks) {
         for (Icon icon : chunks) {
            setLabelIcon(icon);
         }
      }

      private BufferedImage captureScreen() {
         BufferedImage img = robot.createScreenCapture(SCREEN_RECT);
         return img;
      }

   }

   private static void createAndShowGui() {
      SwingWorkerEg mainPanel = new SwingWorkerEg();

      JFrame frame = new JFrame("SwingWorker Eg");
      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();
         }
      });
   }
}

哪个会显示...

在此处输入图像描述

于 2013-04-19T04:18:29.990 回答