1

画面を読み取ってフレームに表示するスレッドを作成しようとしています。このコードは5fpsで実行することを意図しており、これまでのところ画面を読み取りますが、JFrameに「フレーム」ごとに更新画像を表示させるのに問題がありますまたは 200 ミリ秒。repaint(); を使用する場合 または再検証();

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(...)ませんか?
  • 多くのバックグラウンド処理が行われているSwingWorker<Void, Icon>ため、作業を行うために を使用することを検討し、GUI の JLabel に表示される ImageIcon を公開するようにします。これを行った場合、タイミングは SwingWorker のバックグラウンド スレッドで行われるため、おそらく Swing タイマーを使用しないでしょう。

例えば:

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 に答える