在调用扫描程序后,方法不会更新GUI

时间:2014-03-29 20:38:06

标签: java eclipse swing user-interface jframe

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

Driver.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);
    }


}

无论是

还是

1 个答案:

答案 0 :(得分:2)

您遇到了一个线程问题,阻塞方法会阻止您的GUI事件线程冻结您的程序。这是因为您正在尝试将控制台程序与其线性程序逻辑与事件驱动的GUI程序相结合。

解决方案很简单:不要这样做。摆脱你的new Scanner(System.in),只能通过GUI以事件驱动的方式获取用户输入。您可以使用JOptionPane或JDialog来获取此输入,要么效果很好,要么不是new Scanner(System.in)。我自己,我只是使用JOptionPane.showConfirmDialog(...)

作为旁注,您正在使用类名称,例如View和Controller,就像您计划进行模型 - 视图 - 控制类型的程序设计一样, GREAT < / strong>想法,如果你问我,但是控件应该处理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 {

}