【问题标题】:How to stop grid cell from redrawing in Java?如何阻止网格单元在 Java 中重绘?
【发布时间】:2018-02-04 13:49:14
【问题描述】:

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



 }


}

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

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

【问题讨论】:

  • 您需要edit您的问题并创建并发布一个有效的minimal reproducible example,作为代码格式的文本,我们可以编译和运行而无需修改的代码。我看到的一个问题是您上面的paint 方法,可能是在GUI 中的绘画方法中调用的方法,其中包含一些程序逻辑,用于执行随机化的代码。了解随机化不应在绘画代码中完成,而应在其他地方完成,这样它就不会受到您无法控制的重绘的影响。
  • 因为你在循环部分设置了xy的值;因此,无论您之前将它们设置为什么值,当您完成随机颜色部分时,它们将始终设置在屏幕的右下角。
  • 查看编辑以回答

标签: java random graphics colors grid


【解决方案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 命名约定,因为方法名称应以小写字母开头。
  • 您使用了很多“神奇”的数字和值,并希望避免这样做,以使您的代码更加自我注释。

也许更清洁的东西是这样的,使用枚举作为你的地面:

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

【讨论】:

    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    • 2012-05-27
    • 2010-11-17
    • 2013-10-26
    • 2019-06-03
    • 1970-01-01
    相关资源
    最近更新 更多