如果调用 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/