java - 如何在Java中阻止网格单元重绘?

标签 java random graphics colors grid

我正在尝试为网格中的每个单元格生成随机颜色(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;
   }



 }


}

此图显示了当我取出随机颜色的代码时网格的样子。

enter image description here

这个显示了包含的那部分代码:

enter image description here

最佳答案

事实上,这就是我的答案:从绘画代码中取出随机化。相反,为 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 命名约定,因为方法名称应以小写字母开头。
  • 您使用了大量“神奇”的数字和值,并且希望避免这样做,以便使您的代码更具 self 注释性。

也许更干净的是这样的,使用枚举作为你的地面:

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

关于java - 如何在Java中阻止网格单元重绘?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45899558/

相关文章:

java - 线程 "main"java.lang.OutOfMemoryError : GC overhead limit exceeded - Eclipse 中的异常

java - 未找到 Spark RDD 类

Java System.out.println 格式

unity3d - 从 DX9 到 DX11 的顶点着色器编译错误(Unity 5.6 到 2017.4)

java - 让 Jenkins 自动运行失败的测试

python - 比较使用随机数生成的 Matlab 和 Numpy 代码

java - 从集合的迭代器中获取第一项会返回一个随机值吗?

python - 我到底如何(以及为什么)可以通过 numpy.random 访问所有 NumPy?

math - 求解向量的原点

c++ - 向 vulkan 管道添加额外的 UBO 会停止所有几何体渲染