gpt4 book ai didi

java - 我的 Swing 应用程序可能不是线程安全的 - 虽然不知道为什么

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:13:06 24 4
gpt4 key购买 nike

应评论者的要求进行编辑。我希望这是合规的。

第一次发帖!试图理解为什么我的 Swing 应用程序不能从一个面板前进到下一个面板。这是代码的一般流程:

public class MainWindow {

JFrame mainFrame;
ChangeablePanel currentScreen; // abstract and extends JPanel, has getters &
setters for a Timer (swing timer), a String (nextScreen), and an Image
(background image). also has a close(AWTEvent e) method that simply calls
"this.setVisible(false);"

public MainWindow() {
mainFrame = new JFrame("New Arcana");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitleFrame();
} // MainFrame constructor

public void changeFrame(String frameType, String frameName) {
switch (frameType) {
case "Title":
setTitleFrame();
break;
case "Town":
setTownFrame(frameName);
break;
case "Movie":
setMovieFrame(frameName);
break;
default:
break;
} // switch
} // changeFrame

private void setTitleFrame() {
currentScreen = new TitlePanel();
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
} // setTitleFrame

private void setTownFrame(String townName) {
currentScreen = new TownPanel(townName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(townScreenLength, townScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setTownFrame

private void setMovieFrame(String movieName) {
currentScreen = new MoviePanel(movieName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setMovieFrame

private class ScreenChangeListener implements ComponentListener {
@Override
public void componentHidden(ComponentEvent e) {
gotoNextScreen(e);
}

public void componentMoved(ComponentEvent e) {}

public void componentResized(ComponentEvent e) {}

public void componentShown(ComponentEvent e) {}
} // ScreenChangeListener

public void gotoNextScreen(ComponentEvent e) {
changeFrame(currentScreen.getNextScreen(), null);
}
} // MainWindow

public class Start {
...
public static void main(String[] args) {
initialize();

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainWindow();
}
});
} // main
...
} // Start

public class TitlePanel extends ChangeablePanel implements ActionListener {

JButton newGame, continueGame;

public TitlePanel() {
setFocusable(true);
...

newGame = new JButton("New Game");
continueGame = new JButton("Continue");

newGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setNextScreen("Movie");
close(e);
}
});

add(newGame);
add(continueGame);

createTimer(10, this);
getTimer().start();
} // TitlePanel constructor

@Override
public void actionPerformed(ActionEvent e) {
repaint();
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawTitleScreen(g2d);
} // paintComponent

private void drawTitleScreen(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
newGame.setLocation(170, 550);
continueGame.setLocation(605, 550);
} // drawTitleScreen
} // TitlePanel

public class MoviePanel extends ChangeablePanel implements ActionListener {

public MoviePanel(String movieName) {
setFocusable(true);

addKeyListener(new AnyKeyActionListener());
...
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor

@Override
public void actionPerformed(ActionEvent e) {
repaint();
}

public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
drawMovie(g2d);
} // paintComponent

private void drawMovie(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
} // drawTitleScreen

private class AnyKeyActionListener extends KeyAdapter {
public void keyTyped(KeyEvent e) {
setNextScreen("Town");
close(e);
} // keyPressed
} // listener to check for keystrokes
} // MoviePanel

随着应用程序基于用户输入的推进,MainFrame 将填充更多的帧(目前,只有 MoviePanel 和 TownPanel 被编码),它们的代码与这个非常相似——我也粘贴了 MoviePanel。

执行在上面基于 KeyAdapter 的监听器之后中断。但是,当我在带有断点的 Eclipse 中以 Debug模式运行我的应用程序时,这确实完成了它应该做的事情并从 MoviePanel 前进到 TownPanel。正因为如此,我怀疑线程是这里的罪魁祸首。请注意,我确实在上面的代码块上尝试了 SwingUtilities.invokeLater() 技术的许多不同组合,但它没有改变任何东西。任何帮助,将不胜感激;谢谢!

最佳答案

执行以下操作:

  • invokeLater 用于在 GUI 事件调度线程上创建
  • 在构建过程中没有 repaint()
  • 最后设置可见

特别是在事件监听器上再次使用 invokeLater,让按钮等响应,然后采取响应的 Action 。

public static void main(String[] args) {
...
SwingUtilities.invokeLater() {
@Override()
new Runnable() {
new MainFrame().setVisible(true);
}
};
}

代码审查

TitlePanel.TitlePanel 中最好使用绝对布局(即 null),而不是在绘制代码中使用 setLocation

    setLayout(null);
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.setBounds(170, 550, 120, 24);
continueGame.setBounds(605, 550, 120, 24);

ChangeablePanel.close 中也确保 timer.stop()

MainWindow 中使用 invokeLater:

public void gotoNextScreen(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
changeFrame(currentScreen.getNextScreen(), null);
}
});
}

MoviePanel我看不到 addKeyListener 可以运行;也许遗漏的代码?或者这可能是您看到的错误?此外,我发现一个简单的 repaint() 可疑;会期待这样的事情:

public void actionPerformed(ActionEvent e) {
invalidate();
repaint(10L);
}

关于java - 我的 Swing 应用程序可能不是线程安全的 - 虽然不知道为什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11061105/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com