【问题标题】:Method Won't Update GUI After Scanner is Called调用扫描程序后方法不会更新 GUI
【发布时间】:2023-04-02 06:10:01
【问题描述】:

如果调用了cont(),为什么屏幕不会更新为新面板(由theView.continueToGame() 调用)?如果我注释掉ask() 调用cont() 的位置,它似乎有效。有人可以解释为什么会这样吗?似乎有循环的东西把它搞砸了。

驱动程序.java

public class Driver {

    public static void main(String[] args)
    {
        Controller con = new Controller();
        con.ask();
    }

}

Controller.java

public class Controller {

    private View theView = new View();
    private Model theModel = new Model();

    public void ask()
    {
        theView.displayMenu();

        cont();

        System.out.println("ready");

        theView.continueToGame();


    }

    private void cont()
    {
        Scanner stdin = new Scanner(System.in);

        int input = 0;

        while(!(input == 1))
        {
            System.out.println("Enter 1 to continue");
            input = 0;
            try 
            {
                input = stdin.nextInt();
            } 
            catch (InputMismatchException e) 
            {
                System.out.println("error");
                stdin.next();
            }

        }

        stdin.close();
    }
}

View.java

public class View extends JFrame {

    /**
     * Serial id
     */
    private static final long serialVersionUID = 1L;

    private String String1 = "1";
    private String String2 = "2";

    View()
    {
        setVisible(true);
        setTitle("Tic-Tac-Toe");
        setSize(400,400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public void displayMenu()
    {
        this.add(new startMenu());
    }

    public void continueToGame()
    {
        this.getContentPane().removeAll();
        this.add(new gameScreen());
    }

    class startMenu extends JPanel{

        /**
         * Serial id
         */
        private static final long serialVersionUID = 1L;

        private startMenu()
        {
            setVisible(true);
        }

        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            setBackground(Color.blue);

            g.setColor(Color.black);
            g.drawString(String1, this.getWidth()/2, this.getHeight()/2);
        }

    }

    class gameScreen extends JPanel
    {

        /**
         * Serial id
         */
        private static final long serialVersionUID = 1L;

        private gameScreen()
        {
            setVisible(true);
        }

        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            setBackground(Color.green);

            g.setColor(Color.black);

            g.drawString(String2, this.getWidth()/2, this.getHeight()/2);
        }

    }



}

编辑:

cont() 更改为

private void cont()
{
    Integer input = -1;

    while(!(input == 0))
    {

        input = JOptionPane.showConfirmDialog(theView, "Continue?", null, JOptionPane.YES_OPTION);
        System.out.println(input);
    }


}

也不行

【问题讨论】:

    标签: java eclipse swing user-interface jframe


    【解决方案1】:

    您遇到了线程问题,其中阻塞方法正在阻塞您的 GUI 的事件线程冻结您的程序。这是因为您试图将控制台程序及其线性程序逻辑与事件驱动的 GUI 程序结合起来。

    解决方法很简单:不要这样做。摆脱您的new Scanner(System.in),仅通过您的 GUI 以事件驱动的方式获取用户输入。您可以使用 JOptionPane 或 JDialog 来获取此输入,两者都可以,但不是 new Scanner(System.in)。我自己,我会简单地使用JOptionPane.showConfirmDialog(...)

    附带说明一下,您正在使用类名称,例如 View 和 Controller,就好像您打算进行模型-视图-控制类型的程序设计,这是一个 伟大 如果你问我的话,想法,但控件应该处理 GUI 的用户输入,而不是控制台的。


    编辑
    我错了——你的问题是你在交换组件后没有在你的容器上调用revalidate()repaint()。即,

    public void continueToGame()  {
        this.getContentPane().removeAll();
        this.add(new gameScreen());
        revalidate(); // tells layout managers to layout new components
        repaint();  // redraw everything
    }
    

    最好不要担心这些事情并使用 CardLayout 来交换您的视图 JPanel。


    编辑 2
    CardLayout 实际上很容易使用,但是如果将其添加到 JFrame 中,实际上就是将其添加到 contentPane 中,并且在调用 CardLayout 对象的 show 方法时必须使用 contentPane。例如:

    import java.awt.CardLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import javax.swing.*;
    
    public class Driver {
    
       public static void main(String[] args) {
          Controller con = new Controller();
          con.ask();
       }
    }
    
    class Controller {
    
       private View theView = new View();
       private Model theModel = new Model();
    
       public void ask() {
          theView.displayMenu();
    
          if (cont(theView)) {
             System.out.println("ready");
             theView.setView(View.GAME);
          }
       }
    
       private boolean cont(View theView) {
          int result = JOptionPane.showConfirmDialog(theView, "Go on to game?");
          return result == JOptionPane.YES_OPTION;
       }
    }
    
    class View extends JFrame {
    
       private static final long serialVersionUID = 1L;
       public static final String START = "start";
       public static final String GAME = "game";
       private String String1 = "1";
       private String String2 = "2";
       private CardLayout cardLayout = new CardLayout();
    
       View() {
          // setVisible(true); // don't call this til all added to gui
          setTitle("Tic-Tac-Toe");
          // setSize(400, 400); 
          setDefaultCloseOperation(EXIT_ON_CLOSE);
    
          getContentPane().setLayout(cardLayout);
          add(new StartMenu(), START);
          add(new GameScreen(), GAME);
    
          pack();
          setVisible(true);
       }
    
       public void displayMenu() {
          this.add(new StartMenu());
       }
    
       public void setView(String constant) {
          cardLayout.show(getContentPane(), constant);
       }
    
       // class names should begin with an upper case letter
       class StartMenu extends JPanel {
          private static final int PREF_W = 400;
          private static final int PREF_H = PREF_W;
    
          private static final long serialVersionUID = 1L;
    
          private StartMenu() {
             setVisible(true);
          }
    
          @Override
          public Dimension getPreferredSize() {
             return new Dimension(PREF_W, PREF_H);
          }
    
          public void paintComponent(Graphics g) {
             super.paintComponent(g);
             setBackground(Color.blue);
    
             g.setColor(Color.black);
             g.drawString(String1, this.getWidth() / 2, this.getHeight() / 2);
          }
    
       }
    
       // class names should begin with an upper case letter
       class GameScreen extends JPanel {
    
          private static final long serialVersionUID = 1L;
    
          private GameScreen() {
             setVisible(true);
          }
    
          public void paintComponent(Graphics g) {
             super.paintComponent(g);
             setBackground(Color.green);
             g.setColor(Color.black);
             g.drawString(String2, this.getWidth() / 2, this.getHeight() / 2);
          }
    
       }
    }
    
    class Model {
    
    }
    

    【讨论】:

    • 这是有道理的。我只是把它作为一个框架来测试 GUI 的更新方法,但现在我知道它为什么不起作用了。
    • @Strategos:我的建议是正确的,但我对您的错误的解释是错误的。请参阅编辑。
    • 好的,感谢您的帮助。添加这些方法似乎可以解决问题。所以这意味着它甚至可以使用控制台输入。我从未使用过 CardLayout;我想我会检查一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多