java-重新绘制未按要求正常运行

我已经建立了俄罗斯方块游戏.现在,我已经使用JPanel来显示内容和块(使用paintComponents()方法).

问题是,每当我尝试从另一个JFrame调用tetris程序时,它根本不会绘制.

我的俄罗斯方块主菜单的代码是:

import javax.swing.*;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import java.awt.*;
import java.awt.event.*;
import java.io.FileInputStream;
import java.io.InputStream;

@SuppressWarnings("serial")
public class Tetris_MainMenu extends JFrame implements ActionListener {

    @SuppressWarnings("unused")
    public static void main(String[] args) {

        Tetris_MainMenu tmm = new Tetris_MainMenu();
        playAudio("doak.wav");

    }

    JPanel logo = new JPanel();
    JPanel buttonPanel = new JPanel(new GridLayout(4, 1));

    JButton start = new JButton("START NEW GAME");
    JButton help = new JButton("INSTRUCTIONS");
    JButton about = new JButton("ABOUT THIS GAME");
    JButton exit = new JButton("EXIT");

    Tetris_MainMenu(){

        setTitle("JAG's TETRIS");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocation(300, 100);
        setSize(200, 400);
        setEnabled(true);
        setFocusable(true);
        setVisible(true);

        //adding a logo to the logo panel

        //adding buttons to the buttonPanel
        buttonPanel.add(start);
        buttonPanel.add(help);
        buttonPanel.add(about);
        buttonPanel.add(exit);

        //add panels to window
        setLayout(new GridLayout(2, 1));
        add(logo);
        add(buttonPanel);

        //make buttons listen to actions
        start.addActionListener(this);
        help.addActionListener(this);
        about.addActionListener(this);
        exit.addActionListener(this);

    }

    @SuppressWarnings("restriction")
    public static void playAudio(String filename)
    {   
        InputStream in = null;
        AudioStream as = null;
        try{
            in = new FileInputStream(filename);
            as = new AudioStream(in);
        }
        catch(Exception e){
            System.out.println("Error!!!");
        }
        AudioPlayer.player.start(as);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if(e.getSource() == start){
            this.dispose();
            MatrixBoard b = new MatrixBoard();
            b.setRequestFocusEnabled(true);
        }
        else if(e.getSource() == help){
            JOptionPane.showMessageDialog(null, "Controls:\n"
                    + "LEFT and RIGHT ARROWS: For moving blocks left and right\n"
                    + "DOWN ARROW: For dropping block immediately\n"
                    + "SPACEBAR: For rotating block\n"
                    + "e: To exit to main menu");
        }
        else if(e.getSource() == about){
            JOptionPane.showMessageDialog(null, "Designed by: JAG."
                    + "\nIf you want you can use it for your own purposes."
                    + "\nBut give credit where it is due.");
        }
        else if(e.getSource() == exit){
            int opt = JOptionPane.showConfirmDialog(null, "Are you sure?", "Confirm Exit", JOptionPane.YES_NO_OPTION);
            if(opt == JOptionPane.YES_OPTION){
                System.exit(0);
            }
        }
    }


}

当调用MatrixBoard的构造函数时,俄罗斯方块游戏会在新窗口中开始.但是,这些块在屏幕上不可见. MatrixBoard的代码是:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import sun.audio.*;

@SuppressWarnings("serial")
public class MatrixBoard extends JPanel implements ActionListener{

    int boardHeight = 20;
    int boardWidth  = 10;
    int score = 0;
    int curX = 0, curY = 0;
    int squareWidth;
    int squareHeight;
    Timer timer;
    int sleepTime = 300;
    Shape curPiece;
    Shape.Tetromino[][] board;
    boolean isFallingFinished = false;
    boolean isStarted = false;
    boolean isPaused = false;
    JFrame f;

    @SuppressWarnings("unused")
    public static void main(String [] args){
        MatrixBoard b = new MatrixBoard();      
    }

    public void update(Graphics g) {

        Graphics offgc;
        Image offscreen = null;
        Dimension d = getSize();
        // create the offscreen buffer and associated Graphics
        offscreen = createImage(d.width, d.height);
        offgc = offscreen.getGraphics();
        // clear the exposed area
        offgc.setColor(getBackground());
        offgc.fillRect(0, 0, d.width, d.height);
        offgc.setColor(getForeground());
        // do normal redraw
        paint(offgc);
        // transfer offscreen to window
        g.drawImage(offscreen, 0, 0, this);
    }

    @SuppressWarnings("restriction")
    public static void playAudio(String filename)
    {   
        InputStream in = null;
        AudioStream as = null;
        try{
            in = new FileInputStream(filename);
            as = new AudioStream(in);
        }
        catch(Exception e){
            System.out.println("Error!!!");
        }
        AudioPlayer.player.start(as);
    }

    MatrixBoard(){
        f = new JFrame("JAG's TETRIS");
        f.setVisible(true);
        f.setSize(205, 400);
        f.setFocusable(true);
        f.setBackground(Color.GREEN);
        f.add(this);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 400);
        setVisible(true);
        setFocusable(true);
        requestFocusInWindow();
        setBackground(Color.BLACK);
        timer = new Timer(400, this);
        timer.setInitialDelay(10);
        squareWidth = (getWidth())/ boardWidth;
        squareHeight = (getHeight()) / boardHeight;
        curPiece = new Shape();
        board = new Shape.Tetromino[boardWidth][boardHeight];
        addKeyListener(new KeyHandler());
        clearBoard();
        timer.start();
        JOptionPane.showMessageDialog(null, "Press Enter to Start!!!");
        f.setEnabled(true);
        f.setResizable(false);
        //setEnabled(true);
        start();
        System.out.println("MatrixBoard() Success!");
    }

    public void clearBoard(){
        for(int i = 0; i < boardWidth; ++i)
            for(int j = 0; j < boardHeight; ++j)
                board[i][j] = Shape.Tetromino.NoShape;
    }

    public void start()
    {
        if (isPaused)
            return;
        clearBoard();
        timer.start();
        timer = new Timer(400, this);
        timer.setInitialDelay(100);
        isStarted = true;
        isFallingFinished = false;
        score = 0;
        repaint();
        newPiece();
        System.out.println("START SUCCESS!");
    }

    private void newPiece(){
        if(!isStarted) return;
        curPiece.generateShape();
        curX = boardWidth / 2;
        curY = 1;

        if(!tryMove(curPiece, curX, curY)){
            curPiece.selectPiece(Shape.Tetromino.NoShape);
            isStarted = false;
            JOptionPane.showMessageDialog(null, "Game Over! Score : " + score);
            isStarted = false;
            int opt = JOptionPane.showConfirmDialog(null, "Try Again?", "Again?", JOptionPane.YES_NO_OPTION);
            if(opt == JOptionPane.YES_OPTION){
                start();
            }
            else if (opt == JOptionPane.NO_OPTION){
                System.exit(0);
            }
            //dispose();
            System.exit(0);
            //new Tetris();
            return;
        }
        dropDown();
        System.out.println("NEW PIECE SUCCESS!");
    }

    private boolean tryMove(Shape newPiece, int newX, int newY){
        for(int i = 0; i < 4; i++){
            int x = newX + newPiece.coords[i][0]; 
            int y = newY + newPiece.coords[i][1]; 
            if(x < 0 || x >= boardWidth || y < 0 || y >= boardHeight){
                System.out.println("FALSE1");
                return false;
            }
            if(board[x][y] != Shape.Tetromino.NoShape){
                System.out.println("FALSE2");
                return false;
            }
        }
        curPiece = newPiece;
        curX = newX;
        curY = newY;
        System.out.println("curX = " + curX + " curY = " + curY);
        System.out.println("TRY MOVE SUCCESS!");
        return true;
    }

    private void dropDown(){
        int newY = curY;
        sleepTime = 300;
        System.out.println("newY = " + newY);
        while(newY < boardHeight){
            if(!tryMove(curPiece, curX, newY+1)){ break;}
            ++newY;
            System.out.println("calling f.update()");
            repaint();
            System.out.println("called f.update()");
            try {
                Thread.sleep(sleepTime);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        pieceDropped();
        System.out.println("DROPDOWN SUCCESS!");
    }

    private void pieceDropped(){

        for(int i = 0; i < 4; i++){
            int x = curX + curPiece.coords[i][0];
            int y = curY + curPiece.coords[i][1];
            board[x][y] = curPiece.retShape();
            System.out.println("PIECE: at X = " + x + " Y = " + y + "is " + curPiece.retShape().ordinal());
        }
        removeFullLines();
        if(!isFallingFinished) newPiece();
        System.out.println("PIECE DROPPED SUCCESS!");

    }

    public void paintComponent(Graphics g){ 

        System.out.println("PAINTED\n\n\n\n\nPAINTED!!!!");

        super.paintComponent(g);

        Dimension size = getSize();
        int boardTop = (int) size.getHeight() - boardHeight * squareHeight;

        System.out.println("PAINTED\n\n\n\n\nPAINTED!!!!");

        for (int i = 0; i < boardWidth; ++i) {
            for (int j = 0; j < boardHeight; ++j) {
                Shape.Tetromino shape = board[i][j];
                if (shape != Shape.Tetromino.NoShape)
                    drawSquare(g, i * squareWidth,
                               boardTop + j * squareHeight, shape);
            }
        }

        if (curPiece.retShape() != Shape.Tetromino.NoShape) {
           for (int i = 0; i < 4; ++i) {
               int x = curX + curPiece.coords[i][0];
               int y = curY + curPiece.coords[i][1];
               drawSquare(g, x * squareWidth,
                          boardTop + (y - 1) * squareHeight,
                          curPiece.retShape());
           }
       }
   }

    private void drawSquare(Graphics g, int x, int y, Shape.Tetromino shape)
    {
        Color colors[] = { new Color(0, 0, 0), new Color(204, 102, 102), 
            new Color(102, 204, 102), new Color(102, 102, 204), 
            new Color(204, 204, 102), new Color(204, 102, 204), 
            new Color(102, 204, 204), new Color(218, 170, 0)
        };

        Color color = colors[shape.ordinal()];

        g.setColor(color);
        g.fillRect(x + 1, y + 1, squareWidth - 2, squareHeight - 2);

        g.setColor(color.brighter());
        g.drawLine(x, y + squareHeight - 1, x, y);
        g.drawLine(x, y, x + squareWidth - 1, y);

        g.setColor(color.darker());
        g.drawLine(x + 1, y + squareHeight - 1,
                         x + squareWidth - 1, y + squareHeight - 1);
        g.drawLine(x + squareWidth - 1, y + squareHeight - 1,
                         x + squareWidth - 1, y + 1);

    }

    private void removeFullLines(){

        int numLines = 0;

        for(int i = 0; i < boardHeight; i++){
            boolean isLineFull = true;
            for(int j = 0; j < boardWidth; j++){
                System.out.println("i = " + i + " j = " + j);
                if(board[j][i] == Shape.Tetromino.NoShape){
                    System.out.println("Found No Shape here!");
                    isLineFull = false;
                    break;
                }
            }

            System.out.println("IIIIIIIIS LINE : " + isLineFull);

            if(isLineFull){
                numLines++;
                for(int k = i; k > 0; k--){
                    for(int j = 0; j < boardWidth; ++j){
                        board[j][k] = board[j][k-1]; 
                    }
                }
            }
        }

        if(numLines > 0){
            score += numLines * numLines;
            repaint();
            newPiece();
        }

    }

    class KeyHandler extends KeyAdapter{
        public void keyPressed(KeyEvent e){
            if(!isStarted || curPiece.retShape() == Shape.Tetromino.NoShape){
                return;
            }
            int keyCode = e.getKeyCode();

            switch(keyCode){
            case KeyEvent.VK_LEFT:
                tryMove(curPiece, curX - 1, curY);
                break;
            case KeyEvent.VK_RIGHT:
                tryMove(curPiece, curX + 1, curY);
                break;
            case KeyEvent.VK_DOWN:
                sleepTime = 10;
                break;
            case KeyEvent.VK_E:
                int opt = JOptionPane.showConfirmDialog(null,"Are you sure?", "Exit", JOptionPane.YES_NO_OPTION);
                if(opt == JOptionPane.YES_OPTION){
                    System.exit(0);
                }
                break;
            case KeyEvent.VK_SPACE:
                tryMove(curPiece.rotateLeft(), curX, curY);
                break;
            default:
                break;
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isFallingFinished) {
            isFallingFinished = false;
            newPiece();
        } 
    }

}

请帮忙.我怀疑问题出在重绘机制上,但我不确定.

最佳答案
您的问题似乎是Swing线程问题,因为您似乎正在Swing事件线程上调用Thread.sleep(…).这样做将锁定整个线程,从而冻结您的应用程序.不要执行此操作,而应使用Swing计时器.

> Swing Timer Tutorial:有关如何使用Swing计时器的基本教程.
> Concurrency in Swing Tutorial:更多有关Swing事件分配线程(EDT)工作原理的信息.

顺便说一句,您不想覆盖Swing GUI的update()方法,因为它主要用于AWT GUI,除非您在运行中期更改了应用程序的外观.

编辑
你问:

I understand that calling Thread.sleep() is undesirable and it is better to use timers. But the thing is that when I run the MatrixBoard individually, it works perfectly well. The thread issue is not faced here. Please explain if possible.

当您单独调用它时,主应用程序未在Swing线程上运行(这是不应该做的-所有Swing应用程序都应在Swing事件线程上运行),因此您的代码似乎可以正常工作.一旦强迫它在Swing事件线程上运行,它将冻结.

应该使用SwingUtilities.invokeLater(new Runnable(){…});将所有Swing GUI排队到事件线程中.

编辑2

观看更改此内容时会发生什么:

public static void main(String [] args){
    MatrixBoard b = new MatrixBoard();      
}

到更合适的代码:

public static void main(String[] args){
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MatrixBoard b = new MatrixBoard();      
      }
    });
}

我敢打赌,您的MatrixBoard不会冻结(尽管我尚未测试过).

转载注明原文:java-重新绘制未按要求正常运行 - 代码日志