我想让“主线程”(运行 main()
的线程启动)从按钮的 ActionListener 的 actionPerformed()
方法做一些工作, 但我不知道如何实现这一目标。
更多背景信息:
我目前正在使用 Swing(俄罗斯方 block 的一种风格)编写 2D 游戏。
当应用程序启动时,会打开一个显示游戏主菜单的窗口。
向用户提供了几种可能性,其中一种是通过按下“开始”按钮开始游戏,这会导致显示游戏面板并触发游戏的主循环。
为了能够在两个面板(主菜单面板和游戏面板)之间切换,我使用了 CardLayout 管理器,然后我可以通过调用 show()
显示一个面板。 .
我的想法是,我希望我的开始按钮有一个如下所示的监听器:
public class StartListener implements ActionListener {
StartListener() {}
public void actionPerformed(ActionEvent e) {
displayGamePanel();
startGame();
}
}
但这不起作用,因为 actionPerformed()
是从事件派发线程调用的,因此调用 startGame()
(触发主循环:游戏逻辑更新 + repaint()
在每一帧调用)阻塞整个线程。
我现在处理这个的方式是 actionPerformed()
只是改变一个 boolean 标志值:public void actionPerformed(ActionEvent e) {
开始推送=真;
}
然后最终由主线程检查:
while (true) {
while (!g.startPushed) {
try {
Thread.sleep(100);
} catch (Exception e) {}
}
g.startPushed = false;
g.startGame();
}
但我发现这个解决方案非常不优雅。
我已阅读Concurrency in Swing教训,但我仍然感到困惑(我应该实现一个工作线程——这不是有点矫枉过正吗?)。我还没有完成任何实际的多线程工作,所以我有点迷茫。
有没有办法告诉主线程(它会无限期地 hibernate ,等待用户操作)“好的,现在醒来并执行此操作(显示游戏面板并开始游戏)”?。
感谢您的帮助。
编辑: 需要说明的是,这就是我的游戏循环的样子:
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) {}
}
最佳答案
这没有意义:
but this does not work because actionPerformed() is called from the event-dispatch thread, so the call to startGame() (which triggers the main loop: game logic update + repaint() call at each frame) blocks the whole thread.
因为您的游戏循环不应该阻止 EDT。您在游戏循环中使用 Swing Timer 或后台线程吗?如果没有,请这样做。
关于:
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);
}
}
关于Java Swing : How do I wake up the main thread from the event-dispatch thread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10263430/