【问题标题】:GUI running at 30 fps?以 30 fps 运行的 GUI?
【发布时间】:2012-08-07 00:25:20
【问题描述】:

在测试一些使用 Swingworker 的实时模拟代码时,我注意到我的 GUI 似乎总是以 30 fps 运行,不多也不少。每次用户与应用程序交互(如鼠标移动)或调用 Swingworker 的 process() 方法时,我都会更新 GUI。 Swingworker 现在不做任何事情,它只是从 GUI 中获取鼠标位置并通过 publish() 和 process() 方法将其作为克隆发送回(我这样做只是为了看看我能做什么和能做什么'在线程之间进行通信时不要这样做,因为多线程对我来说还是相当新的)。我在任何地方都没有任何计时器,Swingworker 的 process() 方法在 GUI 上调用 repaint(),所以我想知道是什么导致 GUI 以 30 fps 更新?默认情况下,在 GUI 中是否有类似活动的 vsync 或者它是 Swingworker 中 process() 方法的某些行为?最后:有没有办法获得更高的帧率?

这是一个表现出这种行为的 sscce:

public class SimGameTest implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new SimGameTest());
    }

    @Override
    public void run() {
        MainWindow mainWindow = new MainWindow(new Game());

        mainWindow.setLocationRelativeTo(null);
        mainWindow.setVisible(true);
    }
}

public class MainWindow extends JFrame {
    private Game        game;
    private GamePanel   gamePanel;

    public MainWindow(Game game) {
        this.game = game;

        createAndShowGUI();

        startGame();
    }

    private void startGame() {
        GameSim gameSim = new GameSim(game, gamePanel);
        gameSim.execute();
    }

    private void createAndShowGUI() {
        setTitle("Sim game test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);

        JPanel contentPane = new JPanel(new GridBagLayout());

        gamePanel = new GamePanel(game);
        contentPane.add(gamePanel);

        add(contentPane);
        pack();
    }
}

public class Game {
    public Point            mouseLocation       = new Point();
    public Point            clonedMouseLocation = new Point();
}

public class GameSim extends SwingWorker<Point, Point> {
    private Game                game;
    private GamePanel           gamePanel;

    public GameSim(Game game, GamePanel gamePanel) {
        this.game = game;
        this.gamePanel = gamePanel;
    }

    @Override
    protected Point doInBackground() throws Exception {
        while (true) {
            publish((Point) game.mouseLocation.clone());
        }
    }

    @Override
    protected void process(List<Point> pointList) {
        game.clonedMouseLocation = pointList.get(pointList.size() - 1);
        gamePanel.repaint();
    }
}

public class GamePanel extends JPanel {
    private Game                game;
    private long                lastTime;

    public GamePanel(Game game) {
        this.game = game;
        setPreferredSize(new Dimension(512, 512));
    addMouseMotionListener(new GamePanelListener(););
    }

    @Override
    public void paintComponent(Graphics g) {
        // draw background
        g.setColor(new Color(0, 0, 32));
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(new Color(192, 192, 255));
        g.drawString(game.clonedMouseLocation.x + ", " + game.clonedMouseLocation.y, 10, 502);

        long now = System.nanoTime();
        long timePassed = now - lastTime;
        lastTime = now;
        double fps = ((double) 1000000000 / timePassed);
        g.drawString("fps: " + fps, 10, 482);
    }

    private class GamePanelListener extends MouseInputAdapter {
        @Override
        public void mouseMoved(MouseEvent e) {
            if (contains(e.getPoint())) {
                game.mouseLocation = e.getPoint();
            }
        }
    }
}

我创建了另一个版本,我只计算重新绘制 GUI 的次数并在屏幕上显示计数,它似乎以每秒 30 次的速度增加,所以我猜 fps 计算不是问题。

【问题讨论】:

  • 请编辑您的问题以包含一个sscce,以显示您描述的费率。
  • 你是如何获得帧率的?
  • 我平均大约 24fps。我想你会发现它取决于图形管道实现(DX 或 GL)、硬件、操作系统和系统上的全部负载。当我将系统置于负载下时,我还让它下降到 5fps。
  • 我也可以在重负载下将其关闭,但不能启动,所以我想知道是什么导致了这个限制,如果它是 Java 或操作系统本身的一部分。我可以使用不同的技术解决它吗?
  • 切换到主动渲染应该会提高 fps,Passive vs. Active Rendering

标签: java swing swingworker


【解决方案1】:

事实证明,SwingWorker 使用 javax.swing.TimerRunnable 的实例发布到 EventQueue,而 DELAY 恰好是 DELAY

private static class DoSubmitAccumulativeRunnable 
      extends AccumulativeRunnable<Runnable> implements ActionListener {
    private final static int DELAY = (int) (1000 / 30);
    ...
}

您可以获得更高的帧速率,但不能使用javax.swing.SwingWorker。您可以从source 构建SwingWorker,但最终您会用Runnable 的实例使线程饱和。一种替代方法是完全运行模型并定期对其进行采样,如 here 所示。

【讨论】:

  • 我确实使用javax.swing.Timer知道javax.swing.SwingWorker
  • 我昨天在回答this question时发现了这一点
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
相关资源
最近更新 更多