Java JPanel 闪烁

标签 java swing jpanel flicker

我遇到了与 JPanel 中闪烁相关的问题。不知道为什么, window 里的球时不时地闪烁。我尝试了几种方法,比如双缓冲、BufferStrategy、Canvas,但都不起作用。 主要思想是使用线程池,当一个球已经绑定(bind)了几次时,将其删除并创建另一个线程。必须同时有很多球。

这是我的代码:

public class BallWindow extends JFrame {

private static final long serialVersionUID = 1L;
private BallPanel panel;
private final int WINDOW_WIDTH = 700;
private final int WINDOW_HEIGHT = 700;

public BallWindow() {
    super("Balls");
    this.panel = new BallPanel();
    this.panel.setPreferredSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT));
    this.add(panel);
    this.pack();
}

public int getPanelWidth() {
    return panel.getWidth();
}

public int getPanelHeight() {
    return panel.getHeight();
}

public void initGUI() {
    this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setVisible(true);
}
//Balls have to tell to the window to paint them, just once
public void drawMe(BallThread ball) {
    this.panel.drawMe(ball);
}
}


class BallPanel extends JPanel {

private static final long serialVersionUID = 1L;
private Queue<BallThread> queue;

public BallPanel() {
     this.queue = new LinkedList<>();
}

public void drawMe(BallThread ball) {
    this.queue.add(ball);
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    while(queue.peek() != null) {
        queue.poll().drawBall(g2);
    }
} 
}

这是球(它们是线程):

public class BallThread implements Runnable {

private int x;
private int y;
private int dx;
private int dy;
private int diameter;
private int bounces;
private BallWindow window;

public BallThread(int x, int y, int dx, int dy, int diameter, int lBounces, BallWindow window) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.diameter = diameter;
    this.bounces = lBounces;
    this.window = window;
}

public int getX() {
    return x;
}

public void setX(int x) {
    this.x = x;
}

public int getY() {
    return y;
}

public void setY(int y) {
    this.y = y;
}

public void setWindow(BallWindow window) {
    this.window = window;
}

public void drawBall(Graphics2D g) {
    g.setColor(Color.BLUE);
    g.fillOval(this.x, this.y, this.diameter, this.diameter);
}

private void move() {
    this.x += this.dx;
    this.y += this.dy;
    bounce();
    this.window.drawMe(this);
}

private void bounce() {
    if(this.x < 0) {
        this.x = 0;
        this.dx = -dx;
        this.bounces--;
    } else if(this.x+diameter > this.window.getPanelWidth()) {
        this.x = this.window.getPanelWidth()-diameter;
        this.dx = -dx;
        this.bounces--;
    }

    if(this.y < 0) {
        this.y = 0;
        this.dy = -dy;
        this.bounces--;
    } else if(this.y+diameter > this.window.getPanelHeight()) {
        this.y = this.window.getPanelHeight()-diameter;
        this.dy = -dy;
        this.bounces--;
    }
}

@Override
public void run() {
    while(this.bounces > 0) {
        this.move();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    GameLoop.decreaseThreadsWorking();
}

}

游戏循环:

public class GameLoop {

private final int N_BALLS = 20;
private static int nThreadsNow = 0;
private BallWindow window;
private ExecutorService poolThreads;

public GameLoop() {
    this.poolThreads = Executors.newFixedThreadPool(N_BALLS);
    gameLoop();
}

private void gameLoop() {
    window = new BallWindow();
    window.initGUI();

    while(true) {
        while(GameLoop.nThreadsNow < this.N_BALLS) {
            BallThread ball = BallFactory.getInstance().getBall(window);
            this.poolThreads.execute(ball);
            GameLoop.nThreadsNow++;
        }
        window.repaint();

        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public static void decreaseThreadsWorking() {
    GameLoop.nThreadsNow--;
}

public static void main(String[] args) {
    new GameLoop();
}
}

最佳答案

这里有很多强耦合,看起来很奇怪的是球不断地将自己添加到要绘制的队列中。

把那 block 拿出来,让框架按计划重新粉刷。这包括重新绘制所有球,而不是试图跟上不断增加的队列。

关于Java JPanel 闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20519006/

相关文章:

java - JTable 不会刷新

java - 贪吃蛇游戏 Java GUI

java - 在Java中使用图像的问题

java - 为什么 LinkedList 类型不带参数?

java - 用随机颜色绘制形状

java - Java正则表达式

java - 单击按钮后将 JPanel 添加到另一个 JPanel

Java swing gridbaglayout 没有完全填满一行

java - 当 ServerCall 在第一个 ServerInterceptro 中关闭时如何忽略 gRPC(java) ServerInterceptor 的其余部分?

java - 将列表映射到 map 中的 DTO - java