【问题标题】:repaint() doesn't repaint on call?repaint() 不会在调用时重新绘制?
【发布时间】:2015-05-13 14:27:40
【问题描述】:

我正在尝试制作三消游戏。我试图通过首先将需要删除的宝石标记为“黑色”,然后让重力来完成它的工作,从而为实际发生的事情创建一些视觉辅助。我正在努力做到这一点,在我将它们标记为“黑色”后,我打电话给repaint();,但它似乎不起作用。我还尝试按照另一个问题中的建议添加revalidate();,但这似乎也不能解决问题。这是困扰我的一段代码。

故障码:

public void deletePattern(Set<Gem> gemsToDelete){
    for(Gem gem : gemsToDelete)
        gem.setType(7);

    repaint(); //This doesn't seem to work

    doGravity();
    switchedBack = true;
    checkPattern();
}

我想在 doGravity() 之前和增强的 for 循环之后重新绘制电路板。难道是我在doGravity()方法中没有正确使用线程?

这是完整的代码:

Board.java

package Game;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedHashSet;
import java.util.Set;

public class Board extends JPanel{

    final int BOARDWIDTH = 8;
    final int BOARDHEIGHT = 8;

    private static final Color COLORS[] = { new Color(255, 0, 0), new Color(255, 128, 0), new Color(255, 255, 0), new Color(0, 255, 0), new Color(0, 255, 255), new Color(0, 0, 255), new Color(127, 0, 255), new Color(0, 0, 0), new Color(0, 0, 0), new Color(255, 255, 255)};

    boolean isAlive, isPattern, switchedBack;
    boolean isFirstSelected = false;
    Gem[][] gems;
    int fromX, fromY, toX, toY;

    public Board() {
        gems = new Gem[BOARDWIDTH][BOARDHEIGHT];
        addMouseListener(new MouseInputAdapter());
    }

    int cellWidth() { return (int) getSize().getWidth() / BOARDWIDTH; }

    int cellHeight() { return (int) getSize().getHeight() / BOARDHEIGHT; }

    public void start(){
        isPattern = switchedBack = false;
        isAlive = true;
        fillBoard();
        checkPattern();
        switchedBack = false;
    }

    public void paint(Graphics g) {
        super.paint(g);

        for (int x = 0; x < BOARDWIDTH; x++) {
            for (int y = 0; y < BOARDHEIGHT; y++)
                drawCell(g, x, y, gems[x][y]);
        }
    }

    public void fillBoard(){
        for (int x = 0; x < BOARDWIDTH; x++) {
            for (int y = 0; y < BOARDHEIGHT; y++)
                gems[x][y] = new Gem();
        }
    }

    public void drawCell(Graphics g, int x, int y, Gem gem) {
        x = x * cellWidth();
        y = y * cellHeight();

        g.setColor(COLORS[gem.getType()]);
        g.fillRect(x, y, x + cellWidth(), y + cellHeight());
    }

    class MouseInputAdapter extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { selectGems(e); } }

    public void selectGems(MouseEvent e){
        int x = e.getX() / cellWidth();
        int y = e.getY() / cellHeight();
        if(!isFirstSelected) {
            fromX = x;
            fromY = y;
            isFirstSelected = true;
        }else{
            toX = x;
            toY = y;
            if((Math.abs(fromX - toX) == 1 ^ Math.abs(fromY - toY) == 1) & (gems[fromX][fromY].getType() != gems[toX][toY].getType())) {
                switchGems();
                isFirstSelected = false;
            }
        }

    }

    public void switchGems(){
        int tempType = gems[fromX][fromY].getType();
        gems[fromX][fromY].setType(gems[toX][toY].getType());
        gems[toX][toY].setType(tempType);
        checkPattern();

        switchedBack = false;
        repaint();
    }

    public void checkPattern() {
        Set<Gem> gemsToDelete = new LinkedHashSet<>();

        isPattern = false;
        for (int x = 0; x < BOARDWIDTH; x++) {
            for (int y = 0; y < BOARDHEIGHT; y++) {
                if (x + 2 < BOARDWIDTH && (gems[x][y].getType() == gems[x + 1][y].getType()) && (gems[x + 1][y].getType() == gems[x + 2][y].getType())) { //Checks for 3 horizontal gems in a row
                    isPattern = true;
                    gemsToDelete.add(gems[x][y]);
                    gemsToDelete.add(gems[x + 1][y]);
                    gemsToDelete.add(gems[x + 2][y]);
                }
                if (y + 2 < BOARDHEIGHT && (gems[x][y].getType() == gems[x][y + 1].getType()) && (gems[x][y + 1].getType() == gems[x][y + 2].getType())) { //Check for 3 vertical gems in a row
                    isPattern = true;
                    gemsToDelete.add(gems[x][y]);
                    gemsToDelete.add(gems[x][y + 1]);
                    gemsToDelete.add(gems[x][y + 2]);
                }
            }
        }
        if(!gemsToDelete.isEmpty())
            deletePattern(gemsToDelete);

        if(!isPattern && !switchedBack){
            switchedBack = true;
            switchGems();
        }
    }

    public void deletePattern(Set<Gem> gemsToDelete){
        for(Gem gem : gemsToDelete)
            gem.setType(7);

        repaint(); //This doesn't seem to work

        doGravity();
        switchedBack = true;
        checkPattern();
    }

    public void doGravity(){
        try{
            Thread.sleep(1000);
        }catch(InterruptedException e){e.printStackTrace();}
        for (int y = 0; y < BOARDHEIGHT; y++) {
            for (int x = 0; x < BOARDWIDTH; x++) {
                if(gems[x][y].getType() == 7){
                    for (int i = y; i >= 0; i--) {
                        if(i == 0)
                            gems[x][i].setType(gems[x][i].genType());
                        else
                            gems[x][i].setType(gems[x][i-1].getType());
                    }
                }
            }
        }
    }
}

Gem.java

package Game;

public class Gem {

    private int type;

    public Gem(){
        this.type = genType();
    }

    public int genType(){ 
        return (int) (Math.random() * 7);
    }

    public void setType(int type){
        this.type = type;
    }

    public int getType(){
        return type;
    }
}

Game.java

package Game;

import javax.swing.*;

public class Game extends JFrame{

    public Game(){
        Board board = new Board();
        getContentPane().add(board);
        board.start();

        setTitle("Game");
        setSize(600, 600);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args){
        Game game = new Game();
        game.setLocationRelativeTo(null);
        game.setVisible(true);
    }
}

【问题讨论】:

  • 1) public void paint(Graphics g) { super.paint(g); 对于任何应该是 public void paintComponent(Graphics g) { super.paintComponent(g);JComponent 2) 为了尽快获得更好的帮助,请发布 MCVE(最小完整可验证示例)或 SSCCE(简短,自我包含,正确的例子)。
  • 感谢有关 paintComponent 的提示,它并没有解决它,但很高兴知道 :) 我将阅读 MCVE 和 SSCCE(从未听说过它们),如果我可以使用那里学到的信息改进我的问题我将编辑问题。
  • repaint() 请求 UI 线程重新绘制指定的组件。它不会导致绘画直接发生

标签: java multithreading swing paint repaint


【解决方案1】:

您的代码是通过鼠标单击启动的。从 Swing 侦听器调用的代码在 Event Dispatch Thread (EDT) 上执行,它还负责绘制 GUI

doGravaity() 方法中的 Thread.sleep() 会导致 EDT 休眠,因此在整个循环代码完成之前,GUI 无法 repaint() 本身,此时它只会绘制动画的最终状态.

您需要使用Swing Timer 来安排动画,而不是休眠。所以基本上,在deletePattern() 方法中,您将启动 Timer 来执行重力动画。这将释放 EDT 以重新绘制自身,并且当 Timer 触发时,您将为组件设置动画,然后再次执行 repaint()。当组件完成移动时,您将停止计时器。

阅读 Concurrency 上的 Swing 教程部分,了解有关 EDT 的更多信息。

【讨论】:

  • 谢谢,这行得通,还不知道如何继续实现它,但至少我现在有一些简单的东西正在工作:)
  • @RichardKoetschruyter,很高兴这个建议有所帮助。不要忘记通过单击复选标记“接受”答案,这样人们就知道问题已得到回答。
  • 我知道,我很快就会知道,但我仍在阅读其他人的答案
【解决方案2】:

调用this.invalidate()this.postInvalidate(),然后强制重绘。

【讨论】:

  • -1,无效不会强制重绘()。 repaint() 将向 RepaintManager 添加一个绘制请求,RepaintManager 将向 EDT 添加一个绘制请求。
  • -1,无效不会强制重绘()。如果你想重绘一些东西,你调用 repaint()。 repaint() 方法将向 RepaintManager 添加一个绘制请求,RepaintManager 将向 EDT 添加一个绘制请求。
猜你喜欢
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-28
  • 1970-01-01
  • 2011-09-08
相关资源
最近更新 更多