N
N
Nikolay Razumovsky2018-07-19 20:43:40
Java
Nikolay Razumovsky, 2018-07-19 20:43:40

Why does a java application slow down?

I am self-taught in programming and still do not understand everything.
As part of the study of working with a graphical interface, I am making a Minesweeper game. However, the system works with a delay. I click on an object, but there is no reaction. Have to press a few times. Sometimes it works the first time, but not often.

Program
package jsx;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class Minesweeper extends JPanel {

  List<Tile> field;
  Random random;
  boolean inGame;
  boolean isWin;

  public Minesweeper() {
    field = new ArrayList<Tile>();
    random = new Random();

    setPreferredSize(new Dimension(346, 368));
    setFocusable(true);
    addKeyListener(new KeyAdapter() {
      @Override
      public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
          init();
        }
      }
    });
    addMouseListener(new MouseAdapter() {
      @Override
      public void mouseClicked(MouseEvent e) {
        if (inGame) {
          if (e.getButton() == MouseEvent.BUTTON1) {
            Tile tile = getTile(e.getX(), e.getY());
            if (tile == null)
              return;

            clickLeft(tile);
          } else if (e.getButton() == MouseEvent.BUTTON3) {
            Tile tile = getTile(e.getX(), e.getY());
            if (tile == null)
              return;

            clickRight(tile);
          }
        } else {
          init();
        }
      }
    });
    init();
  }

  void init() {
    inGame = true;
    isWin = false;
    for (int x = 0; x < 9; x++) {
      for (int y = 0; y < 9; y++) {
        field.add(new Tile(x, y));
      }
    }
    for (int i = 0; i < 9; i++) {
      Tile t = field.get(random.nextInt(field.size()));
      if (t.isMined()) {
        i--;
      } else {
        t.setMined();
        for (Tile t0 : getNearby(t)) {
          t0.setValue(t0.getValue() + 1);
        }
      }
    }
    repaint();
  }

  List<Tile> getNearby(Tile t) {
    List<Tile> out = new ArrayList<Tile>();
    for (Tile tile : field) {
      if (t.isNear(tile)) {
        out.add(tile);
      }
    }
    return out;
  }

  int getInt(int i) {
    if (i < 18) {
      return -1;
    }
    for (int c = 1; c < 10; c++) {
      if (i < 18 + 32 * c) {
        return c - 1;
      }
    }
    return -1;
  }

  Tile getTile(int x, int y) {
    x = getInt(x);
    y = getInt(y);
    if (x > -1 && y > -1) {
      for (Tile t0 : field) {
        if (t0.getX() == x && t0.getY() == y) {
          return t0;
        }
      }
    }
    return null;
  }

  void clickRight(Tile tile) {
    if (tile.isFlag(Flag.NONE)) {
      tile.setFlag(Flag.MARKED);
    } else if (tile.isFlag(Flag.MARKED)) {
      tile.setFlag(Flag.NONE);
    }

    repaint();
  }

  void clickLeft(Tile tile) {
    if (!tile.isFlag(Flag.NONE))
      return;

    // losing
    if (tile.isMined()) {
      inGame = false;
      for (Tile t0 : field) {
        if (t0.isMined()) {
          if (t0.isFlag(Flag.MARKED)) {
            t0.setFlag(Flag.VERIFIED);
          } else {
            t0.setFlag(Flag.ERROR);
          }
        } else {
          t0.setFlag(Flag.CRUSHED);
        }
      }

    } else {
      tile.setFlag(Flag.OPEN);

      // TODO check win

    }

    repaint();
  }

  enum Flag {
    NONE, OPEN, MARKED, CRUSHED, ERROR, VERIFIED;
  }

  static class Tile {

    private boolean mined;
    private int value, x, y;
    private Flag flag;

    public Tile(int x, int y) {
      this.mined = false;
      this.value = 0;
      this.x = x;
      this.y = y;
      this.flag = Flag.NONE;
    }

    public boolean isNear(Tile t) {
      return Math.abs(x - t.getX()) < 2 && Math.abs(y - t.getY()) < 2;
    }

    public int getX() {
      return x;
    }

    public int getY() {
      return y;
    }

    public boolean isMined() {
      return mined;
    }

    public void setMined() {
      this.mined = true;
    }

    public int getValue() {
      return value;
    }

    public void setValue(int i) {
      this.value = i;
    }

    public boolean isFlag(Flag f) {
      return flag == f;
    }

    public Flag getFlag() {
      return flag;
    }

    public void setFlag(Flag f) {
      this.flag = f;
    }
  }

  @Override
  public void paint(Graphics g) {
    super.paint(g);
    g.setColor(new Color(255, 223, 94));
    g.fillRect(0, 0, 346, 368);
    for (Tile t : field) {
      drawTile(g, t);
    }
  }

  Color getTileTextColor(int i) {
    switch (i) {
    case 1:
      return new Color(0, 45, 183);
    case 2:
      return new Color(22, 122, 0);
    case 3:
      return new Color(183, 0, 0);
    case 4:
      return new Color(0, 10, 163);
    case 5:
      return new Color(183, 0, 0);
    case 6:
      return new Color(140, 184, 255);
    case 7:
      return new Color(183, 0, 0);
    case 8:
      return new Color(147, 0, 160);
    }
    return null;
  }

  void drawTile(Graphics gr, Tile tile) {
    Graphics2D g = ((Graphics2D) gr);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
    int oX = 18 + tile.getX() * 34;
    int oY = 18 + tile.getY() * 34;
    // 166, 0, 14

    if (tile.isFlag(Flag.OPEN)) {
      g.setColor(new Color(221, 234, 255));
      g.fillRect(oX, oY, 32, 32);

      if (tile.getValue() > 0) {
        g.setColor(getTileTextColor(tile.getValue()));
        Font font = new Font("Arial", Font.BOLD, 18);
        g.setFont(font);
        FontMetrics fm = getFontMetrics(font);
        int w = fm.stringWidth(String.valueOf(tile.getValue()));
        int h = -(int) fm.getLineMetrics(String.valueOf(tile.getValue()), g).getBaselineOffsets()[2];

        g.drawString(String.valueOf(tile.getValue()), oX + (32 - w) / 2, oY + 32 - (32 - h) / 2 - 2);
      }
    } else if (tile.isFlag(Flag.MARKED)) {
      g.setColor(new Color(43, 102, 196));
      g.fillRect(oX, oY, 32, 32);

      g.setColor(new Color(255, 255, 255));
      Font font = new Font("Arial", Font.BOLD, 18);
      g.setFont(font);
      FontMetrics fm = getFontMetrics(font);
      int w = fm.stringWidth("?");
      int h = -(int) fm.getLineMetrics("?", g).getBaselineOffsets()[2];

      g.drawString("?", oX + (32 - w) / 2, oY + 30 - (32 - h) / 2);

    } else if (tile.isFlag(Flag.CRUSHED)) {
      g.setColor(new Color(186, 37, 0));
      g.fillRect(oX, oY, 32, 32);
    } else if (tile.isFlag(Flag.VERIFIED)) {
      g.setColor(new Color(22, 188, 0));
      g.fillRect(oX, oY, 32, 32);
    } else if (tile.isFlag(Flag.ERROR)) {
      g.setColor(new Color(255, 251, 30));
      g.fillRect(oX, oY, 32, 32);
    } else if (tile.isFlag(Flag.NONE)) {
      g.setColor(new Color(43, 102, 196));
      g.fillRect(oX, oY, 32, 32);
    }

    if (!inGame) {
      g.setColor(new Color(255, 255, 255, 30));
      g.fillRect(0, 0, getWidth(), getHeight());
      g.setColor(new Color(44, 44, 44));
      g.setFont(new Font("Arial", Font.BOLD, 80));
      if (isWin) {
        g.drawString("Win!", 110, 201);
      } else {
        g.drawString("Lose!", 110, 201);
      }
    }
  }

  public static void main(String[] args) {
    JFrame game = new JFrame();
    game.setTitle("Minesweeper");
    game.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    game.setSize(346, 368);
    game.setResizable(false);

    game.add(new Minesweeper());

    game.setLocationRelativeTo(null);
    game.setVisible(true);
  }

}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry Osipov, 2018-07-31
@Shiftuia

First, try debugging the program by writing a test case with test data and running the debug.
Second, try writing a test for all methods, testing their behavior. This will be very useful to you in the future
. Third, if you don't find a bug, configure JMX and look at the resources consumed by the application.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question