java - 调用扫描器后方法不会更新 GUI

标签 java eclipse swing user-interface jframe

如果调用 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);
    }


}

也不起作用

最佳答案

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

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

顺便说一句,您正在使用类名称,例如 View 和 Controller ,就好像您计划进行模型- View -控制类型的程序设计,这是伟大 如果你问我我的想法,但控件应该处理 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 来交换您的 View 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 {

}

关于java - 调用扫描器后方法不会更新 GUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22736590/

相关文章:

java - 正确使用 BigDecimal

java - 在java中以有效的方式在文本框中显示串口输出数据

java - 从 eclipse 自动构建 GAE maven 项目

java - 如果类 B 的实例是类 A 的成员,那么当类 B 中的按钮被按下时,类 B 如何调用类 A 的方法?

java - 缩短变量以利用路径

java - 我想我在这里遗漏了一些东西——string.replace()

java - 在 java 中绘制图形 - NetBeans IDE

JavaScript : Jump to method definition using eclipse

eclipse - 如何使用Gradle将JOGL javadoc路径添加到Eclipse?

java - GUI 中的 JButton