Java Swing: How to wake up the main thread from the event stream?

I want to call the "main thread" (the initial thread that starts main()) to do some work using the actionPerformed()ActionListener button method, but I don't know how to do this.

A bit more context:

I am currently programming a 2D game using Swing (Tetris flavor).
When the application starts, a window opens in which the main menu of the game is displayed. The user is offered several options, one of which is to start the game by pressing the "Start" button, which causes the display of the game panel and starts the main game cycle.

To be able to switch between two panels (in the main menu and in the game), I use the CardLayout manager, then I can display one panel by calling show().
The idea is that I would like my start button to have a listener that looks like this:

public class StartListener implements ActionListener {
    StartListener() {}
    public void actionPerformed(ActionEvent e) {
        displayGamePanel();
        startGame();
    }
}

but this does not work, because it is called from the event-event stream actionPerformed(), so the call startGame()(which starts the main loop: updating logical logic + repaint()on each frame) blocks the entire thread.

The way I'm handling this right now is that it actionPerformed()simply changes the value of the boolean flag: public void actionPerformed(ActionEvent e) { startPushed = true; }
which is then eventually checked by the main thread:

while (true) {
    while (!g.startPushed) {
        try { 
            Thread.sleep(100); 
        } catch (Exception e) {}
    }
    g.startPushed = false;
    g.startGame();
}

But I think this decision is very inelegant.

Concurrency Swing, ( Worker Thread - , overkill?). , .

( , ) ", ( )"?

.

EDIT: , :

long lastLoopTime = System.currentTimeMillis();
long dTime;
int delay = 10;
while (running) {
    // compute the time that has gone since the last frame
    dTime = System.currentTimeMillis() - lastLoopTime;
lastLoopTime = System.currentTimeMillis();

    // UPDATE STATE
    updateState(dTime);
    //...

    // UPDATE GRAPHICS
    // thread-safe: repaint() will run on the EDT
    frame.repaint()

    // Pause for a bit
    try { 
    Thread.sleep(delay); 
    } catch (Exception e) {}
}
+3
5

SwingWorker, doInBackground() , done() EDT doInBackground()

+1

:

, - actionPerformed(), startGame() ( : + () ) .

EDT. Swing ? , .

:

while (true) {
    while (!g.startPushed) {
        try { 
            Thread.sleep(100); 
        } catch (Exception e) {}
    }
    g.startPushed = false;
    g.startGame();
}

, .

.

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class GameState extends JPanel {
   private CardLayout cardlayout = new CardLayout();
   private GamePanel gamePanel = new GamePanel();
   private StartPanel startpanel = new StartPanel(this, gamePanel);

   public GameState() {
      setLayout(cardlayout);
      add(startpanel, StartPanel.DISPLAY_STRING);
      add(gamePanel, GamePanel.DISPLAY_STRING);
   }

   public void showComponent(String displayString) {
      cardlayout.show(this, displayString);
   }

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

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

class StartPanel extends JPanel {
   public static final String DISPLAY_STRING = "Start Panel";

   public StartPanel(final GameState gameState, final GamePanel gamePanel) {
      add(new JButton(new AbstractAction("Start") {

         @Override
         public void actionPerformed(ActionEvent e) {
            gameState.showComponent(GamePanel.DISPLAY_STRING);
            gamePanel.startAnimation();
         }
      }));
   }
}

class GamePanel extends JPanel {
   public static final String DISPLAY_STRING = "Game Panel";
   private static final int PREF_W = 500;
   private static final int PREF_H = 400;
   private static final int RECT_WIDTH = 10;
   private int x;
   private int y;

   public void startAnimation() {
      x = 0;
      y = 0;
      int timerDelay = 10;
      new Timer(timerDelay , new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            x++;
            y++;
            repaint();
         }
      }).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.fillRect(x, y, RECT_WIDTH, RECT_WIDTH);
   }

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

: CountDownLatch. 1, Swing , await .

0

SwingUtilities.invokeAndWait(), .

0
source

You can do all the code except run EDT in a single thread execution service, and then just send runnables whenever you need some code.

0
source

All Articles