Как остановить перерисовку ячейки сетки в Java?

Я пытаюсь создать случайный цвет (между 4 цветами) для каждой ячейки в сетке. Мне удалось это сделать, но он продолжает перерисовывать контур сетки и другие элементы сетки. Как я могу сделать так, чтобы цвета рисовались только один раз?, в то время как другие мои элементы продолжают рисовать себя? Вот код, который у меня сейчас есть:

import java.awt.*;
import java.util.Random;

public class Cell extends Rectangle {

private Random random;

public Cell(int x, int y) {

    super(x, y, 35, 35);
}


public void paint(Graphics g, Boolean highlighted) {

    int row;
    int col;

    for (row=0; row < 20 ; row++ ) {
        for (col =0; col <20 ; col++) {
            x=col * 35;
            y=row * 35;
            SurfaceType(g);
        }
    }


    g.setColor(Color.BLACK);
    g.drawRect(x, y, 35, 35);


    if (highlighted) {
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(x, y, 35, 35);
    } else {
        g.setColor(Color.DARK_GRAY);
        g.fillRect(x, y, 35, 35);
    }

}



@Override
public boolean contains(Point target){
    if (target == null)
        return false;
    return super.contains(target);
}

public void SurfaceType(Graphics g) {
   random= new Random();
   int randomNumber = random.nextInt( 5);

   switch (randomNumber) {
       case 1: // dirt
           g.setColor(new Color(102,51,0));
           g.fillRect(x,y,34,34);
           break;
       case 2: //grass
           g.setColor(new Color(102,153,0));
           g.fillRect(x,y,34,34);
           break;
       case 3: //tree
           g.setColor(new Color(0,102,0));
           g.fillRect(x,y,34,34);
           break;
       case 4: //rock
           g.setColor(new Color(182,182,182));
           g.fillRect(x,y,34,34);
           break;
   }



 }


}

На этом изображении показано, как выглядит сетка, когда я убираю код, который рандомизирует цвет.

введите здесь описание изображения

И это показано с включенной частью кода:

введите здесь описание изображения


person Dan    schedule 26.08.2017    source источник
comment
Вы захотите отредактировать свой вопрос, а также создать и опубликовать действительный минимальный воспроизводимый пример в виде текста в формате кода, кода, который мы можем скомпилировать и запустить без необходимости модификации. Одна проблема, которую я вижу, заключается в том, что ваш метод paint выше, который предположительно вызывается в методе рисования в графическом интерфейсе, содержит в себе некоторую программную логику, код для выполнения рандомизации. Поймите, что рандомизация должна выполняться не в коде отрисовки, а в другом месте, чтобы на нее не влияли перерисовки, которые находятся вне вашего контроля.   -  person Hovercraft Full Of Eels    schedule 26.08.2017
comment
Поскольку вы устанавливаете значение x и y в части цикла; поэтому независимо от того, какое предыдущее значение вы установили для них, к тому времени, когда вы закончите часть случайного цвета, они всегда будут установлены в правом нижнем углу экрана.   -  person meowgoesthedog    schedule 26.08.2017
comment
Смотрите правки, чтобы ответить   -  person Hovercraft Full Of Eels    schedule 27.08.2017


Ответы (1)


На самом деле, это мой ответ: убрать рандомизацию из вашего кода рисования. Вместо этого дайте классу Cell метод, скажем, с именем randomize(), который выполняет рандомизацию цветов и вызывается только тогда, когда вы хотите, чтобы он вызывался, и удалите этот код из кода рисования.

Почему это важно? Поймите, что при использовании Swing отрисовка не полностью находится под вашим контролем, что вы можете предложить отрисовку, вызвав repaint(), но это не гарантируется всегда (особенно если запросы на перерисовку "стекаются"), а также иногда ОС сделает запрос к JVM о том, что происходит рисование, и это полностью вне вашего контроля. Так что методы рисования должны делать только рисование и ничего больше. Любой код, который значительно изменяет состояние ваших объектов, например код рандомизации, принадлежит другому месту.

Например:

import java.awt.*;
import java.util.Random;

public class Cell extends Rectangle {
    // no magic numbers
    private static final Color DIRT_COLOR = new Color(102, 51, 0);
    private static final Color GRASS_COLOR = new Color(102,153,0);
    private static final Color TREE_COLOR = new Color(0, 102, 0);
    private static final Color ROCK_COLOR = new Color(182, 182, 182);
    private static final int CELL_WIDTH = 35;
    private static final int RECT_WIDTH = CELL_WIDTH - 1;
    private Color cellColor = null;
    private Random random;

    public Cell(int x, int y) {
        super(x, y, CELL_WIDTH, CELL_WIDTH);
    }

    // highlighted should be a boolean primitive, not a Boolean wrapper
    public void paint(Graphics g, boolean highlighted) {
        int row;
        int col;

        // **** these nested for loops don't look right
        // as this Cell should draw itself and only itself
        for (row = 0; row < 20; row++) {
            for (col = 0; col < 20; col++) {
                x = col * CELL_WIDTH;
                y = row * CELL_WIDTH;

                // don't call surfactType() here, but rather *****
                // simply draw with cellColor   *******
                if (cellColor != null) {
                    g.setColor(cellColor);
                    g.fillRect(x, y, RECT_WIDTH, RECT_WIDTH);
                }
            }
        }
        g.setColor(Color.BLACK);
        g.drawRect(x, y, CELL_WIDTH, CELL_WIDTH);
        if (highlighted) {
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
        } else {
            g.setColor(Color.DARK_GRAY);
            g.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
        }
    }

    @Override
    public boolean contains(Point target) {
        if (target == null)
            return false;
        return super.contains(target);
    }

    // ** Rename this from SurfaceType to surfaceType
    public void surfaceType() {
        random = new Random();
        int randomNumber = random.nextInt(5);
        switch (randomNumber) {
        case 1: // dirt
            cellColor = DIRT_COLOR;
            break;
        case 2: // grass
            cellColor = GRASS_COLOR;
            break;
        case 3: // tree
            cellColor = TREE_COLOR;
            break;
        case 4: // rock
            cellColor = ROCK_COLOR;
            break;
        }
    }
}

Теперь ваш код GUI может вызывать surfaceType() для рандомизации ячейки, когда это необходимо, и вызывать repaint() после изменения состояния. Случайная картина не изменит состояние ячейки.

Другие несвязанные проблемы с вашим кодом:

  • Ваш метод рисования с вложенным циклом for пытается закрасить все ячейки, а не только текущую, и это выглядит неправильно. Вместо этого он должен заниматься только самой живописью.
  • Ваш код не полностью соответствует соглашениям об именах Java, поскольку имена методов должны начинаться со строчной буквы.
  • Вы используете много «магических» чисел и значений и хотите избежать этого, чтобы сделать свой код гораздо более самокомментирующим.

Возможно, чище было бы что-то в этом роде, используя enum для вашего Ground:

import java.awt.Color;

public enum Ground {
    DEFAULT(null), // Not sure if you need a default 
    DIRT(new Color(102, 51, 0)), 
    GRASS(new Color(102,153,0)), 
    TREE(new Color(0,102,0)), 
    ROCK(new Color(182,182,182));

    private Ground(Color color) {
        this.color = color;
    }

    private Color color;

    public Color getColor() {
        return color;
    }

    public static Ground getRandom() {
        int randomIndex = (int) (Math.random() * Ground.values().length);
        return Ground.values()[randomIndex];
    }
}

и для Cell2

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;

public class Cell2 {
    private static final int CELL_WIDTH = 35;
    private static final Stroke STROKE = new BasicStroke(3f);
    private Rectangle rect; // favor composition over inheritance
    private Ground ground;

    public Cell2(int x, int y) {
        rect = new Rectangle(x, y, CELL_WIDTH, CELL_WIDTH);
    }

    public void paint(Graphics2D g2, boolean highlighted) {
        if (ground != null && ground != Ground.DEFAULT) {
            g2.setColor(ground.getColor());
            g2.fill(rect);
        }
        g2.setStroke(STROKE);
        Color c = highlighted ? Color.LIGHT_GRAY : Color.DARK_GRAY;
        g2.setColor(c);
        g2.draw(rect);
    }

    public void randomizeGround() {
        ground = Ground.getRandom();
    }

    public boolean contains(Point p) {
        return rect.contains(p);
    }
}
person Hovercraft Full Of Eels    schedule 26.08.2017