重绘未按要求正常运行

2023-12-13

我制作了一个俄罗斯方块游戏。现在我已经使用 JPanel 来显示内容和块(使用 PaintComponents() 方法)。

问题是每当我尝试从另一个 JFrame 调用俄罗斯方块程序时,它根本不绘制。

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

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


}

当调用 Matrix Board 的构造函数时,俄罗斯方块游戏将在新窗口中启动。但是,这些块在屏幕上不可见。矩阵板的代码是:

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 线程问题,因为您似乎正在调用Thread.sleep(...)在 Swing 事件线程上。这样做将锁定整个线程,冻结您的应用程序。不要这样做,而是使用 Swing Timer。

  • Swing 定时器教程:关于如何使用 Swing Timers 的基本教程。
  • Swing 教程中的并发:有关 Swing 事件调度线程 (EDT) 如何工作的更多信息。

顺便说一句,你不想覆盖update()方法适用于 Swing GUI,因为这主要适用于 AWT GUI,除非您在运行中更改应用程序的外观和感觉。


Edit
你问:

我知道调用 Thread.sleep() 是不可取的,最好使用计时器。但问题是,当我单独运行 MatrixBoard 时,它运行得非常好。这里没有遇到线程问题。如果可能的话请解释一下。

当您单独调用它时,主应用程序不会在 Swing 线程上运行(这不是应该做的事情 - 所有 Swing 应用程序)should在 Swing 事件线程上运行),所以您的代码seems上班。一旦强制它在 Swing 事件线程上运行,它就会冻结。

所有 Swing GUI 都应使用以下命令将其排队到事件线程中SwingUtilities.invokeLater(new Runnable() {...});


Edit 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 不会冻结(尽管我还没有测试过)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重绘未按要求正常运行 的相关文章

随机推荐

  • 如何从ObjectInputStream读取所有对象

    我有一个包含一些信息的文件 如何读取所有信息 Name names try FileInputStream fileInputStream new FileInputStream file ObjectInputStream objectI
  • 尝试使用 PHP 和 fpdf 显示 pdf 文件

    背景 这是一个电子学习网站 当用户处于学习阶段时 它会在前3页显示供阅读的内容 之后需要用户进行测试 当用户克服所有挑战后 它会显示pdf证书 目前的问题是 到达最后一页后 它总是显示一些奇怪的单词 以下是全部 PDF 1 3 3 0 ob
  • Java中的尾递归函数仍然会破坏堆栈

    我正在尝试实现尾递归阶乘计算器 但仍然出现堆栈溢出 谁能帮我找出原因吗 我读过 Java 8 支持 Tail 调用优化 但我想我一定没有正确实现它 我读到可以使用 lambda 表达式 我不确定我是否完全理解这个概念 但我仍在阅读 我只是在
  • 如何防止动态宽度弹性盒子项溢出父项?

    在下面的示例中 我想防止拉伸的子项溢出父项 我不想为其指定宽度 我怎样才能做到这一点 flex parent display flex width 200px background green padding 10px fixed chil
  • Angular 5 ng build --prod 装饰器中不支持函数表达式

    我正在尝试构建我的项目 当我只是在本地运行它时 该项目运行良好ng serve but on ng b prod我得到 ERROR in app logged in content routing routing component ts
  • React.js:将参数传递给事件处理程序的最有效方法,无需在组件中使用bind()

    当事件处理程序使用this 就像handleClick下面使用this setState 你必须绑定事件处理程序this关键词 否则 您需要使用箭头函数 e g This function isn t bound whilst using
  • 如何使用nodejs从角度获得相当于“req.something”的内容

    我正在关注有关如何使用 Node js 和护照设置身份验证的教程 http scotch io tutorials javascript easy node authentication setup and local 本教程让我使用 ej
  • gdb 中的下一个命令无法正常工作

    我只是使用 gdb 逐行浏览代码 以了解它是如何工作的以及它在做什么 我第一次执行此操作时效果很好 但现在下一个命令无法正常工作 有时它前进 有时它倒退 这没有道理 每次我这样做时 似乎都是相同的模式 下面是一个例子 有人知道出了什么问题吗
  • Android NDK:尝试移植 JnetPcap

    我发现了一个Android流量监控应用程序 Shark 它基于 JnetPcap 并且有一个包含所有源文件和相应的文件Android mk files 我将 jni 目录放在 Android NDK 的示例文件中 并尝试使用ndk buil
  • 可以在构造函数外部赋值的只读字段

    有没有办法在类中拥有一个私有只读字段 可以在类中的任何位置赋值 但只能赋值一次 也就是说 我正在寻找一种私有只读类型的字段 它只能被赋值一次 但不一定在构造函数内 因此 如果将一个值重新分配给一个字段 那么它会显示编译时错误 我确信这要求太
  • 从 JOOQ 解析器结果中获取表/列元数据

    使用 JOOQ 解析器 API 我能够解析以下查询并从结果查询对象中获取参数映射 由此 我可以看出有一个参数 它的名字是 something 但是 我无法弄清楚如何确定参数 something 已分配给名为 BAZ 的列 并且该列是表 BA
  • 即时生成自签名证书

    我四处搜寻 但没有找到明确的例子 我想以编程方式创建一个自签名 自 信任的证书 C 按照以下步骤操作 STEP 1 即时创建根 CA 证书并将其添加到 受信任的根证书颁发机构 文件夹中的证书存储中 我想做的正是这个命令行工具所做的事情 ma
  • 无法从shinyapps.io连接到Microsoft Azure

    我构建了一个从 Microsoft Azure 提取数据的 Rshiny 应用程序 当我在连接字符串中使用 SQL Server 驱动程序时 我的应用程序可以在本地运行 但当我在shinyapps io 上发布应用程序时 我的应用程序无法运
  • Angular 2 中的兄弟事件通信

    我当时的项目中有五个组件 它们是 1 AppComponent Main component 2 AuthComponent 3 HomeComponent 4 HeaderComponent 5 FooterComponent AppCo
  • 当内容高度 > 2000px 时,WP7 ScrollViewer 错误

    在我的项目中 我使用ScrollViewer显示一些长的高度信息 我这样使用
  • 以编程方式将内容添加到 TreeViewItem

    我正在尝试创建一个新的 TreeViewItem 其中包含一个控件 如下所示
  • 倒计时器?

    如何制作倒计时器 当用户加载页面时 时钟开始倒计时 到达时间后 它将浏览器重定向到新页面 找到这个了 不太好用 http encosia com 2007 07 25 display data updates in real time wi
  • FFMPEG iOS 7 库

    我尝试阅读很多教程 我花了几个小时在谷歌和 stackoverflow 上尝试回答 到目前为止我读过 尝试使用armv6和arv7架构为iPhoneOS平台编译FFMPEG库 FFMPEG 在 iphone ipad 项目上的集成 and
  • 使用 LESS 递归函数和媒体查询生成样式

    我正在尝试生成一些相对于屏幕高度的内容 并决定尝试使用 LESS 来生成类似的内容 即使作为测试有点重 baseHeight 1px setRelativeHeight screenHeight minHeightDiff maxHeigh
  • 重绘未按要求正常运行

    我制作了一个俄罗斯方块游戏 现在我已经使用 JPanel 来显示内容和块 使用 PaintComponents 方法 问题是每当我尝试从另一个 JFrame 调用俄罗斯方块程序时 它根本不绘制 我的俄罗斯方块主菜单的代码是 import j