【问题标题】:Creating and Discarding JFrames that run Threads创建和丢弃运行线程的 JFrame
【发布时间】:2020-03-26 01:06:17
【问题描述】:

我正在使用 Java Swing 编写俄罗斯方块。 Game 类围绕着一个 JFrame(框架),它由一个 TetrisPanel 扩展 JPanel(面板)组成,一个 JLabel(pontok)点计数器,一个显示高分的 JTextArea(rekord_text)和另一个显示高分的 JPanel(kovi)下一个要倒下的街区。我的想法是游戏有 3 个难度级别,其中积木以不同的速度下落。

我认为解决此问题的最佳方法是使用上述组件创建一个新的 JFrame,但块的速度设置不同。我能够关闭旧的 JFrame。但是当新的JFrame打开时,它只是一个空白框,并不会响应关闭窗口。

我应该补充一点,TetrisPanel 正在运行一个线程,但我 90% 确定我会用一个 volatile 布尔值来停止它。

游戏类的构造函数:

        this.difSet(nehezseg);  //this function sets the falling velocity
        TetrisPanel.stopped = true;  //this static member is the volatile boolean responsible for stopping the thread
        new_game = false;

        frame = new JFrame("Tetris_alpha");

        frame.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();

        panel = new TetrisPanel();
        TetrisPanel.stopped = false;
        new Thread(panel).start();
        frame.add(panel, c);

        pontok = new JLabel ("0");
        frame.add(pontok, c);

        rekord_text = new JTextArea();
        //i set up the area
        frame.add(rekord_text, c);

        kovi = new NextAktualPanel();
        frame.add(kovi, c);

        menu = new MyMenu(this);
        frame.setJMenuBar(menu);

        frame.addWindowListener(new WindowAdapter()
            {
                @Override
                public void windowClosing(WindowEvent e)
                    {
                        rekordok.add(panel.getPont());
                        rekordok.write(f);
                        e.getWindow().dispose();
                        System.exit(0);
                    }
                }
        );

        frame.pack();
        frame.setVisible(true);
    }

包含游戏循环的 Game.start() 函数:

public void start()
    {
        //game_loop
        while (!panel.GameOver() && !new_game)
        {
                if (panel.aktualLeertDetector())
                {   
                    panel.addAktualToBlocks();
                    panel.addNewAktual(next);
                    Elem temp = new Elem(0,0,rand.nextInt(7)); 
                    while (temp.getTipus() == next.getTipus())
                        temp = new Elem(0,0,rand.nextInt(7));
                    next = temp;
                    kovi.setNextAktual (next);
                }
                if (!paused)
                    pontok.setText(Integer.toString(panel.getPont()));
                kovi.repaint();
                panel.repaint();
        }

打开新框架的函数:

Public void newGame (Game g)
{
            Game.new_game = true;
            g.frame.dispose();
            Game new_game = new Game("easy");
            g = new_game;
            g.start();
}

还有TetrisPanel的run()函数:

public static volatile boolean stopped = false;
@Override
    public void run() {
        while (!stopped)
        {
            aktual.zuhan();
            this.sorTeleAction();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

任何帮助都将不胜感激,包括有关不同方法的想法。

【问题讨论】:

  • Swing 不应由 AWT 事件调度线程以外的线程使用。如果您想延迟时间,请使用javax.swing.Timer(注意不要混淆使用同名的其他计时器)。
  • 您的代码似乎违反了 Swing 线程规则。如果您还没有阅读Concurrency in Swing,那么现在是个好时机,因为此链接将解释这些规则、如何遵循它们以及它们为何重要。那么是的,按照@TomHawtin 的建议去做——使用Swing Timer 来驱动你的游戏循环。
  • 我认为解决这个问题的最好方法是用组件创建一个新的 JFrame - 不需要创建一个新的 JFrame。您的游戏逻辑只需要一个“重置”方法。当您使用 JTextField 时,您只需使用 setText(...) 来更改文本。当您使用 JTable 时,您只需更改 TableModel。在任何一种情况下,您都不会创建新组件。

标签: java swing jframe jpanel java-threads


【解决方案1】:
  1. 不要使用 volatile boolean 作为状态变量,而是使用 AtomicBoolean,volatile 它不是做这种事情的正确方法,它也不会导致“立即变量更新”......这不是 volatile 的目的。
  2. 在主 AWT 线程上启动线程不是一个好主意,您仍然必须使用 SwingUtilities.invokeLater(Runnable runnableAction)。你可以在启动 Gui Thread 时使用这样的东西:

    
    
    SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        new Thread(threadAction).start();
                    } catch (Exception e) {
                    }
                }
          });
    
    

希望这能解决你的问题!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    相关资源
    最近更新 更多