在方法中初始化后如何正确显示JFrame

鲍里舍

这是一个很长的问题,请耐心等待一分钟。我正在制作一个“生活游戏”应用程序,该应用程序首先显示带有JButtons网格的JFrame。如果单击JButton,其背景将变为黑色,再次激活后,其背景将变为白色。我的代码:

public class Choose implements ActionListener {
public final static int DIMENSION = 50;
Color BLACK = new Color(0,0,0);
Color WHITE = new Color(255,255,255);
JFrame choose;
JButton[] choice;
JButton clear, fill, go;
JPanel baseChoose, baseFrame, buttonsAndText;
GridLayout base;

public Choose() {
    choose = new JFrame("Make your own game");
    choice = new JButton[DIMENSION*DIMENSION];

    baseChoose = new JPanel();
        baseChoose.setSize(500, 500);
    buttonsAndText = new JPanel();

    buttonsAndText.add(clear = new JButton("Clear"));
        clear.addActionListener(this);
    buttonsAndText.add(fill = new JButton("Fill"));
        fill.addActionListener(this);
    buttonsAndText.add(go = new JButton("Go"));
        go.addActionListener(this);

    base = new GridLayout(DIMENSION, DIMENSION);
        base.setHgap(-1);
        base.setVgap(-1);

    baseChoose.setLayout(base);
    choose.add(baseChoose);
    choose.add(buttonsAndText);

    JLabel text = new JLabel("Press 'Go' to start.");
    buttonsAndText.add(text);

    for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
        baseChoose.add(choice[i] = new JButton());
        choice[i].setBackground(WHITE);
        choice[i].addActionListener(this);
    }

    choose.setSize(500, 800);
    choose.setVisible(true);
    choose.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    choose.setResizable(false);
}

public void actionPerformed(ActionEvent e) {
    JButton b = (JButton)e.getSource();

    for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
        if (b == choice[i]) {
            if (b.getBackground() == BLACK) {
                choice[i].setBackground(WHITE);
            } else if (b.getBackground() == WHITE) {
                choice[i].setBackground(BLACK);
            }
        }
    }

    if (b == clear) {
        for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
            choice[i].setBackground(WHITE);
        }
        choose.validate();
        choose.repaint();
    }

    if (b == fill) {
        for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
            choice[i].setBackground(BLACK);
        }
        choose.validate();
        choose.repaint();
    }

    if (b == go) {
        int states[] = new int[DIMENSION*DIMENSION];
        for (int i = 0; i < DIMENSION*DIMENSION; i++) {
            System.out.println(choice[i].getBackground() == BLACK);
            if (choice[i].getBackground() == BLACK) {
                states[i] = 1;
            } else if (choice[i].getBackground() == WHITE) {
                states[i] = 0;
            }
        }
        choose.dispose();
        Gui own = new Gui(states);
    }
}
}

在主要方法中,我创建了该类的一个实例,当您选择要激活的按钮时,可以单击该go按钮以实际显示“生命游戏”。

public class Gui  {
public final static int DIMENSION = 50;
Color BLACK = new Color(0,0,0);
Color WHITE = new Color(255,255,255);
JFrame frame, ownFrame;
JPanel baseFrame;
GridLayout base;

public Gui(int[] states) {
    frame = new JFrame("Game of Life by Boris Verwoerd");

    baseFrame = new JPanel();
        baseFrame.setSize(500, 500);

    frame.add(baseFrame);

    base = new GridLayout(DIMENSION, DIMENSION);
        base.setHgap(-1);
        base.setVgap(-1);

    baseFrame.setLayout(base);

    JPanel[] box = new JPanel[DIMENSION*DIMENSION];

    for (int i = 0; i < (DIMENSION*DIMENSION); i++) {
        baseFrame.add(box[i] = new JPanel());
        box[i].setBorder(BorderFactory.createLineBorder(Color.black));
    }

    frame.setSize(500, 500);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.validate();
    frame.repaint();

    gameLoop(box, frame, states);
}

private static void gameLoop(JPanel[] boxes, JFrame theFrame, int[] states) {
    int[] newstates = new int[DIMENSION*DIMENSION];
    for (int i = 0; i < 20; i++) {

        newstates = Maths.render(boxes, theFrame, states);
        states = newstates;
        theFrame.validate();
        theFrame.repaint();

        try {
            Thread.sleep(100);                 //1000 milliseconds is one second.
        } catch(InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
}

public static int getDim() {
    return DIMENSION;
}

}

当按下go键时,一个新的JFrame会启动,但屏幕完全是白色的,仅在gameLoop结束后才显示JPanel网格。

只有当我从main方法使用全零数组创建Gui的实例时,states它才能正确显示它。我已经尝试了很多方法来提出解决方案,但是我不明白为什么它会导致白色屏幕而不是网格。因此,我的问题是:从方法初始化时,如何在没有白屏的情况下正确显示Gui的实例?

  • 抱歉,很长的帖子/代码!

编辑:

这是我的数学课:

public class Maths {
static Color BLACK = new Color(0,0,0);
static Color WHITE = new Color(255,255,255);

public static int[] render(JPanel[] box, JFrame frame, int[] state) {
    int[] newstates = new int[Gui.getDim()*Gui.getDim()];
    for (int i = 0; i < (Gui.getDim()*Gui.getDim()); i++) newstates[i] = 0;

    for (int i = (Gui.getDim()+1); i < (Gui.getDim()*Gui.getDim() - (Gui.getDim()+1)); i++) {
        if (state[i] == 1) {
            int aliveNeighbours = 0;
            if (state[i-(Gui.getDim()+1)] == 1) aliveNeighbours++;
            if (state[i-Gui.getDim()] == 1) aliveNeighbours++;
            if (state[i-(Gui.getDim()-1)] == 1) aliveNeighbours++;
            if (state[i-1] == 1) aliveNeighbours++;
            if (state[i+1] == 1) aliveNeighbours++;
            if (state[i+(Gui.getDim()-1)] == 1) aliveNeighbours++;
            if (state[i+Gui.getDim()] == 1) aliveNeighbours++;
            if (state[i+(Gui.getDim()+1)] == 1) aliveNeighbours++;

            if (aliveNeighbours == 2 || aliveNeighbours == 3) {
                box[i].setBackground(BLACK);
                newstates[i] = 1;
            } else {
                box[i].setBackground(WHITE);
                newstates[i] = 0;
            }

        } else if (state[i] == 0) {
            int aliveNeighbours = 0;
            if (state[i-(Gui.getDim()+1)] == 1) aliveNeighbours++;
            if (state[i-Gui.getDim()] == 1) aliveNeighbours++;
            if (state[i-(Gui.getDim()-1)] == 1) aliveNeighbours++;
            if (state[i-1] == 1) aliveNeighbours++;
            if (state[i+1] == 1) aliveNeighbours++;
            if (state[i+(Gui.getDim()-1)] == 1) aliveNeighbours++;
            if (state[i+Gui.getDim()] == 1) aliveNeighbours++;
            if (state[i+(Gui.getDim()+1)] == 1) aliveNeighbours++;

            if (aliveNeighbours == 3) {
                box[i].setBackground(BLACK);
                newstates[i] = 1;
            } else {
                box[i].setBackground(WHITE);
                newstates[i] = 0;
            }
        }
    }
    return newstates;
}
}
充满鳗鱼的气垫船

您的问题是Swing线程问题的典型案例,这是由于您的代码运行时间很长,还需要调用Thread.sleep(...)Swing事件线程,这会使整个GUI处于休眠状态,当然这不是您的目标。

解决方案与任何类似的问题相同(在此处发布之前,应该已经搜索并找到了类似的问题):如果您有长时间运行的代码,请使用SwingWorker进行后台线程处理,或者使用Swing计时器以延迟方式周期性地调用代码。

您在此处使用的速度取决于速度Maths.render如果计算速度非常快,那么您只需要一个Swing计时器即可间歇地且延迟地进行此调用。如果此方法需要大量时间才能执行,那么您将需要执行SwingWorker路线。

例如,计时器代码如下所示:

private void gameLoop() {
  int timerDelay = 100;
  new Timer(timerDelay, new ActionListener() {
     private final int maxIndex = 20;
     private int index = 0;

     @Override
     public void actionPerformed(ActionEvent e) {
        if (index < maxIndex) {
           states = Maths.render(box, frame, states);
           frame.validate();
           frame.repaint();
      } else {
           ((Timer) e.getSource()).stop();
        }
        index++;
     }
  }).start();
}

注意gameLoop应该是一个非静态实例方法。我也不允许参数传递,而是使该类的这些家伙领域:

private JPanel[] box;
private int[] states;

并确保设置以下字段:

public Gui(int[] states) {
  this.states = states;
  frame = new JFrame("Game of Life by Boris Verwoerd");

  baseFrame = new JPanel();
  baseFrame.setSize(500, 500);

  frame.add(baseFrame);

  base = new GridLayout(DIMENSION, DIMENSION);
  base.setHgap(-1);
  base.setVgap(-1);

  baseFrame.setLayout(base);

  box = new JPanel[DIMENSION * DIMENSION];

  for (int i = 0; i < (DIMENSION * DIMENSION); i++) {
     baseFrame.add(box[i] = new JPanel());
     box[i].setBorder(BorderFactory.createLineBorder(Color.black));
  }

  frame.setSize(500, 500);
  frame.setVisible(true);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setResizable(false);
  frame.validate();
  frame.repaint();

  gameLoop();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

用JPanel初始化JFrame的正确方法

来自分类Dev

在NetBeans中初始化后JFrame没有出现

来自分类Dev

在NetBeans中初始化后,JFrame没有出现

来自分类Dev

在TinyMCE中初始化后修改工具栏的正确方法

来自分类Dev

初始化16x2 LCD后,如何用8051在LCD中显示字符?

来自分类Dev

在JS对象中初始化此属性的正确方法

来自分类Dev

在Swift 1.1中覆盖初始化程序的正确方法

来自分类Dev

初始化容器中对象的正确方法/模式

来自分类Dev

在Python中初始化全局变量的正确方法

来自分类Dev

在HTML中初始化变量的正确方法

来自分类Dev

在C ++中初始化结构内数组的正确方法

来自分类Dev

正确的方法在骨架.js中初始化jquery库

来自分类Dev

在python中更改初始化对象的正确方法

来自分类Dev

如何正确初始化猫鼬集合中的文档

来自分类Dev

如何正确初始化C ++中的对象向量?

来自分类Dev

如何正确管理构造函数中的初始化?

来自分类Dev

初始化后如何自动调用特定的类方法?

来自分类Dev

初始化后在构造函数中调用方法

来自分类Dev

调用类后在初始化中运行方法

来自分类Dev

初始化后如何更改DataTables中的数据数组

来自分类Dev

如何在初始化+ Netbeans设计视图上隐藏JFrame的组件:彩色显示

来自分类Dev

正确的数据初始化方法

来自分类Dev

正确的Rails初始化方法调用

来自分类Dev

处理失败初始化的正确方法

来自分类Dev

如何正确取消初始化OpenSSL

来自分类Dev

如何正确初始化比较器?

来自分类Dev

如何正确初始化地图?

来自分类Dev

如何正确初始化游标?

来自分类Dev

如何正确初始化类?扑