2012-08-07 22 views
6

Podczas testowania kodu symulacyjnego w czasie rzeczywistym, który wykorzystuje Swingworker zauważyłem, że mój GUI zawsze działa z prędkością 30 klatek na sekundę, nie więcej, nie mniej. Aktualizuję GUI za każdym razem, gdy użytkownik wchodzi w interakcję z aplikacją (jak ruch myszy) lub gdy wywoływana jest metoda process() Swingworker. Swingworker nic teraz nie robi, po prostu chwyta lokalizację myszy z GUI i wysyła ją z powrotem jako klon za pomocą metod publish() i process() (robię to po to, aby zobaczyć, co mogę i mogę kiedy komunikujesz się między wątkami, ponieważ wielowątkowość jest dla mnie całkiem nowa). Nie mam żadnych timerów w dowolnym miejscu, metoda process() wywołań Swingworker repaint() na GUI, więc zastanawiałem się, co powoduje, że GUI aktualizuje się z prędkością 30 fps? Czy w GUI jest prawdopodobnie aktywny kontrakcjonariusz, czy jest to pewne zachowanie metody process() w Swingworker? I wreszcie: czy istnieje sposób na zwiększenie liczby klatek na sekundę?GUI z 30 fps?

Oto sscce który wykazuje takie zachowanie:

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

stworzyłem inną wersję, gdzie po prostu policzyć ile razy GUI został przemalowany i pokazać liczyć na ekranie, a wydaje się, że rośnie w stawka 30 na sekundę, więc domyślam się, że obliczenie fps nie jest problemem.

+2

Edytuj swoje pytanie, dołączając [sscce] (http://sscce.org/), które pokazuje stawkę, którą opisujesz. – trashgod

+2

W jaki sposób uzyskujesz liczbę klatek na sekundę? –

+0

Przepraszam, dodałem sscce – FinalArt2005

Odpowiedz

10

Okazuje się SwingWorker posty wystąpień Runnable do EventQueue użyciu javax.swing.Timer z dokładnie tego DELAY.

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

Możesz uzyskać większą liczbę klatek na sekundę, ale nie w przypadku javax.swing.SwingWorker. Możesz zbudować SwingWorker z source, ale ostatecznie nasycasz wątek instancjami Runnable. Jedną z opcji jest uruchomienie modelu na płasko i okresowe pobieranie próbki, jak pokazano na stronie: here.

+0

Zrobiłem _nie_ wiem o 'javax.swing.SwingWorker' przy użyciu' javax.swing.Timer'. – trashgod

+1

Teraz wszyscy robimy - dzięki! –

+0

Odkryłem, że wczoraj podczas odpowiadania [to pytanie] (http://stackoverflow.com/questions/11825281/java-swing-running-on-edt) – Robin