有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java图形绘制持续闪烁

我试着做一个俄罗斯方块游戏。但是我的jframe GUI持续闪烁。但是当我在代码中注释下面的行时,它不会闪烁。有人能帮忙吗

map.draw((Graphics2D) g);

JDK版本-1.8 NetBeans-7.4

代码文件链接如下

package GUI;

import Maps.MapGenerator;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Timer;

public class BrickBreaker extends javax.swing.JFrame implements KeyListener, ActionListener {

private MapGenerator map;

public BrickBreaker() {
    initComponents();
    this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
    this.setTitle("Test Tetris");
    //Map
    map = new MapGenerator(3, 7);
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
    time = new Timer(delay, this);
    time.start();
}

public void paint(Graphics g) {

    //background
    g.setColor(Color.black);
    g.fillRect(1, 1, 692, 592);

    //map
    map.draw((Graphics2D) g);

    //score
    g.setColor(Color.white);
    g.setFont(new Font("serif", Font.BOLD, 25));
    g.drawString("" + score, 560, 30);

    //border
    g.setColor(Color.yellow);
    g.fillRect(0, 0, 3, 592);
    g.fillRect(0, 0, 692, 3);
    g.fillRect(691, 0, 3, 592);

    //paddle
    g.setColor(Color.green);
    g.fillRect(playerPosX, 550, 100, 8);

    //ball
    g.setColor(Color.red);
    g.fillOval(ballPosX, ballPosY, 20, 20);

    g.dispose();
}

private boolean play = false;
private int score = 0;
private int totalBricks = 21;

private Timer time;
private int delay = 8;

private int playerPosX = 310;

private int ballPosX = 210;
private int ballPosY = 350;
private int ballXDir = -1;
private int ballYDir = -2;

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setPreferredSize(new java.awt.Dimension(700, 600));

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 525, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGap(0, 403, Short.MAX_VALUE)
    );

    pack();
}// </editor-fold>                        

public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(BrickBreaker.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new BrickBreaker().setVisible(true);
        }
    });
}

// Variables declaration - do not modify                     
// End of variables declaration                   
@Override
public void keyTyped(KeyEvent e) {
}

@Override
public void keyPressed(KeyEvent e) {
    try {

        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            if (playerPosX >= 600) {
                playerPosX = 600;
            } else {
                moveRight();
            }
        }

        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            if (playerPosX < 10) {
                playerPosX = 10;
            } else {
                moveLeft();
            }
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public void moveRight() {
    play = true;
    playerPosX += 20;
}

public void moveLeft() {
    play = true;
    playerPosX -= 20;
}

@Override
public void keyReleased(KeyEvent e) {
}

@Override
public void actionPerformed(ActionEvent e) {
    time.start();

    if (play) {

        if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
            ballYDir = -ballYDir;
        }

        A:
        for (int i = 0; i < map.map.length; i++) {
            for (int j = 0; j < map.map[0].length; j++) {
                if (map.map[i][j] > 0) {
                    int brickX = j * map.brickWidth + 60;
                    int brickY = i * map.brickHeight + 50;
                    int brickWidht = map.brickWidth;
                    int brickHeight = map.brickHeight;

                    Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
                    Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
                    Rectangle brickRect = rect;

                    if (ballRect.intersects(brickRect)) {
                        map.setBrickValue(0, i, j);
                        totalBricks--;
                        score += 2;

                        if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
                            ballXDir = -ballXDir;
                        } else {
                            ballYDir = -ballYDir;
                        }

                        break A;
                    }
                }
            }
        }

        ballPosX += ballXDir;
        ballPosY += ballYDir;
        if (ballPosX < 0) {
            ballXDir = -ballXDir;
        }
        if (ballPosY < 0) {
            ballYDir = -ballYDir;
        }
        if (ballPosX > 670) {
            ballXDir = -ballXDir;
        }
    }
    repaint();

}
}

地图生成器

package Maps;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;


public class MapGenerator {

public int map[][];
public int brickWidth;
public int brickHeight;

public MapGenerator(int row, int col) {
    map = new int[row][col];
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            map[i][j] = 1;
        }
    }

    brickWidth = 240 / row;
    brickHeight = 150 / col;
}

public void draw(Graphics2D g) {
    for (int i = 0; i < map.length; i++) {
        for (int j = 0; j < map[0].length; j++) {
            if (map[i][j] > 0) {
                g.setColor(Color.black);
                g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

                g.setStroke(new BasicStroke(3));
                g.setColor(Color.white);
                g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);

            }
        }
    }
}

public void setBrickValue(int value, int row, int col) {
    map[row][col] = value;
}

}

共 (1) 个答案

  1. # 1 楼答案

    顶级容器,如JFrame不是双缓冲的,这导致了闪烁

    这只是不应该重写顶级容器的paint的众多原因之一。相反,从一个JPanel开始并覆盖它的paintComponent,Swing组件在默认情况下会为您自动进行双缓冲

    看看Performing Custom PaintingPainting in AWT and Swing了解更多关于绘画如何在摇摆中工作的细节

    一个更合适的解决方案可能看起来像这样

    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private boolean play = false;
            private int score = 0;
            private int totalBricks = 21;
    
            private Timer timer;
            private int delay = 8;
    
            private int playerPosX = 310;
    
            private int ballPosX = 210;
            private int ballPosY = 350;
            private int ballXDir = -1;
            private int ballYDir = -2;
            private MapGenerator map;
    
            public TestPane() {
                setBackground(Color.BLACK);
                map = new MapGenerator(3, 7);
                timer = new Timer(delay, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (play) {
    
                            if (new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerPosX, 550, 100, 8))) {
                                ballYDir = -ballYDir;
                            }
    
                            for (int i = 0; i < map.map.length; i++) {
                                for (int j = 0; j < map.map[0].length; j++) {
                                    if (map.map[i][j] > 0) {
                                        int brickX = j * map.brickWidth + 60;
                                        int brickY = i * map.brickHeight + 50;
                                        int brickWidht = map.brickWidth;
                                        int brickHeight = map.brickHeight;
    
                                        Rectangle rect = new Rectangle(brickX, brickY, brickWidht, brickHeight);
                                        Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
                                        Rectangle brickRect = rect;
    
                                        if (ballRect.intersects(brickRect)) {
                                            map.setBrickValue(0, i, j);
                                            totalBricks ;
                                            score += 2;
    
                                            if (ballPosX + 19 <= brickRect.x || ballPosX + 1 >= brickRect.x + brickRect.width) {
                                                ballXDir = -ballXDir;
                                            } else {
                                                ballYDir = -ballYDir;
                                            }
                                        }
                                    }
                                }
                            }
    
                            ballPosX += ballXDir;
                            ballPosY += ballYDir;
                            if (ballPosX < 0) {
                                ballXDir = -ballXDir;
                            }
                            if (ballPosY < 0) {
                                ballYDir = -ballYDir;
                            }
                            if (ballPosX > 670) {
                                ballXDir = -ballXDir;
                            }
                        }
                        repaint();
                    }
                });
                timer.start();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(700, 600);
            }
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
    
                //map
                map.draw((Graphics2D) g);
    
                //score
                g.setColor(Color.white);
                g.setFont(new Font("serif", Font.BOLD, 25));
                g.drawString("" + score, 560, 30);
    
                //border
                g.setColor(Color.yellow);
                g.fillRect(0, 0, 3, 592);
                g.fillRect(0, 0, 692, 3);
                g.fillRect(691, 0, 3, 592);
    
                //paddle
                g.setColor(Color.green);
                g.fillRect(playerPosX, 550, 100, 8);
    
                //ball
                g.setColor(Color.red);
                g.fillOval(ballPosX, ballPosY, 20, 20);
    
                g2d.dispose();
            }
    
        }
    
        public class MapGenerator {
    
            public int map[][];
            public int brickWidth;
            public int brickHeight;
    
            public MapGenerator(int row, int col) {
                map = new int[row][col];
                for (int i = 0; i < map.length; i++) {
                    for (int j = 0; j < map[0].length; j++) {
                        map[i][j] = 1;
                    }
                }
    
                brickWidth = 240 / row;
                brickHeight = 150 / col;
            }
    
            public void draw(Graphics2D g) {
                for (int i = 0; i < map.length; i++) {
                    for (int j = 0; j < map[0].length; j++) {
                        if (map[i][j] > 0) {
                            g.setColor(Color.black);
                            g.fillRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
    
                            g.setStroke(new BasicStroke(3));
                            g.setColor(Color.white);
                            g.drawRect(j * brickWidth + 60, i * brickHeight + 50, brickWidth, brickHeight);
    
                        }
                    }
                }
            }
    
            public void setBrickValue(int value, int row, int col) {
                map[row][col] = value;
            }
    
        }
    
    }
    

    观察

    这个

    A:
    for (int i = 0; i < map.map.length; i++) {
        //...
                //...
                    break A;
    

    这是一个糟糕设计的好迹象。在好的代码中应该不需要基于“goto”或“label”的跳转

    你必须在一组非常线性的操作中考虑你的“主循环”,更新状态,检查冲突,更新UI。保持简单,保持快速

    您还将发现the Key Bindings API将解决KeyListener的所有继承问题