2012-08-07 6 views
6

Beim Testen eines Echtzeit-Simulationscodes, der einen Swingworker verwendet, bemerkte ich, dass meine GUI immer mit 30 fps läuft, nicht mehr und nicht weniger. Ich aktualisiere die GUI jedes Mal, wenn der Benutzer mit der Anwendung interagiert (wie eine Mausbewegung) oder wenn die Methode process() des Swingworker aufgerufen wird. Der Swingworker macht gerade nichts, er greift nur die Mausposition von der GUI und sendet sie als Klon durch die Methoden publish() und process() zurück (ich mache das nur, um zu sehen, was ich kann und kann) t tun, wenn zwischen Threads kommunizieren, weil Multithreading noch ziemlich neu für mich ist). Ich habe keine Timer, die process() - Methode des Swingworker ruft repaint() auf der GUI auf, also frage ich mich, was die GUI dazu bringt, mit 30 fps zu aktualisieren? Gibt es vielleicht einen vsync, der standardmäßig in der GUI aktiv ist oder ist es ein Verhalten der process() Methode im Swingworker? Und schließlich: Gibt es eine Möglichkeit, höhere Frameraten zu erzielen?GUI läuft mit 30 fps?

Hier ist ein sscce, die dieses Verhalten zeigt:

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(); 
      } 
     } 
    } 
} 

ich eine andere Version erstellt, wo ich die Anzahl der Male, zählen nur die GUI neu gestrichen wurde und die Zählung auf dem Bildschirm zeigen, und es scheint ein zu steigen Rate von 30 pro Sekunde, also denke ich, die FPS-Berechnung ist nicht das Problem.

+2

Bearbeiten Sie Ihre Frage so, dass sie eine [sscce] (http://sscce.org/) enthält, die die von Ihnen beschriebene Rate aufweist. – trashgod

+2

Wie erhalten Sie die Bildrate? –

+0

Sorry, hinzugefügt eine sscce – FinalArt2005

Antwort

10

Es stellt sich heraus SwingWorker Beiträge Instanzen Runnable zum EventQueue genau einem javax.swing.Timer Verwendung mit diesen DELAY.

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

Sie können eine höhere Bildrate, aber nicht mit javax.swing.SwingWorker. Sie können SwingWorker von source erstellen, aber schließlich sättigen Sie den Thread mit Instanzen von Runnable. Eine Alternative besteht darin, das Modell flach auszuführen und es periodisch zu testen, wie in here gezeigt.

+0

Ich habe 'javax.swing.SwingWorker' nicht mit' javax.swing.Timer' kennengelernt. – trashgod

+1

Jetzt machen wir alle - danke! –

+0

Ich entdeckte, dass gestern während der Beantwortung [dieser Frage] (http://stackoverflow.com/questions/11825281/java-swing-running-on-edt) – Robin