重绘不会更新屏幕

2024-05-07

我想重新粉刷我的屏幕。到目前为止,它所做的只是在第一个屏幕上显示一个点,即头部应该在的位置。这很好,但是我在代码中写道,我希望每秒将头部向下移动 10 像素。我正在打印头部应该在的位置,并且在命令提示符中显示 y 值确实在增加。然而在我的屏幕上,头部没有移动。

我尝试过使用 revalidate 方法,尝试扩展 canvas 类而不是 jframe,我尝试过仅针对 Paint 方法使用不同的类,我尝试过用 PaintComponent 方法替换 Paint 方法。正如你可能知道的那样,我对与 Java 绘画相关的任何事情的理解都不太好。我尝试过阅读这些超类,但它们太复杂了,我无法理解。我也尝试过在没有睡眠声明的情况下运行。这并不重要。

主要类别: 该类包含开始运行贪吃蛇游戏的主要方法。

import java.util.concurrent.TimeUnit;

public class Main{

    public static void main(String[] args) throws InterruptedException {
        Main programma = new Main();
        programma.rungame();
    }

void rungame() throws InterruptedException {
        AllGUIElements gui = new AllGUIElements();
        gui.gui();
        while (true) {
            TimeUnit.SECONDS.sleep(1);
            gui.setGameScreen();
        }
    }
}

AllGUIElements 类:此类创建一个新框架,其中包含一个新面板。该面板正在使用paintComponent 进行绘制。 setGameScreen 更新头部的位置并应该重新绘制屏幕。

import javax.swing.*;
import java.awt.*;

public class AllGUIElements extends JPanel {

    private JFrame frame;
    private JPanel panel;

    private int screen;

    Snake hoofd = new Head(new Point(30,30),3,null);

    void gui() throws InterruptedException {

        frame = new JFrame("Snake Game");
        panel = new AllGUIElements();
        panel.setBackground(Color.GRAY);
        panel.setSize(1000,500);
        frame.setSize(1000,500);
        frame.add(panel);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

void setGameScreen() {
    repaint();
        if (hoofd.getDirection() == 1) {
            hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y-10));
        }
        if (hoofd.getDirection() == 2) {
            hoofd.setPosition(new Point(hoofd.getPosition().x+10, hoofd.getPosition().y));

        }
        if (hoofd.getDirection() == 3) {
            hoofd.setPosition(new Point(hoofd.getPosition().x, hoofd.getPosition().y+10));

        }
        if (hoofd.getDirection() == 4) {
            hoofd.setPosition(new Point(hoofd.getPosition().x-10, hoofd.getPosition().y));
        }
}

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
            g.setColor(Color.DARK_GRAY);
            g.fillRect(0, 0, 1000, 10);
            g.fillRect(0, 0, 10, 500);
            g.fillRect(990, 0, 10, 500);
            g.fillRect(0, 490, 1000, 10);

            g.setColor(Color.GREEN);
            g.fillRect(hoofd.getPosition().x, hoofd.getPosition().y, 10, 10);
    }

}

Screen Object 类:Snake 和 Food 的父类(因为没有必要,所以没有发布),返回头部、身体部位和食物的位置。

import java.awt.*;

public class Screenobject{

    Point pos;

    Screenobject(Point pos){
        this.pos = pos;
    }

    void setPosition(Point pos){
        this.pos = pos;
    }

    Point getPosition() {
        return pos;
    }
}

Snake 类:Screenobject 的子级,Head 和 Body 的父级。此类设置对象的方向。

import java.awt.*;

public class Snake extends Screenobject{

    int direction;
    //directions:
    //1 = up
    //2 = right
    //3 = down
    //4 = left

    Snake nextpart;

    Snake(Point pos, int direction, Snake nextpart){
        super(pos);
        this.direction = direction;
        this.nextpart = nextpart;
    }

    int getDirection() {
        return direction;
    }
}

Head类:snake的子类,应该是snake链表的第一个对象。

import java.awt.*;

public class Head extends Snake{
    Head(Point pos, int direction, Snake nextpart){
        super(pos, direction, nextpart);
    }
}

身体类别:蛇的子级,每吃一次食物就会生长。

import java.awt.*;

public class Body extends Snake{
    Body(Point pos, int direction, Snake nextpart){
        super(pos, direction, nextpart);
    }

}

首先要做的事情是:

我使用“分而治之”的方法只发布必要的信息

是的,您只发布了必要的信息,但您仍然使用了太多的类MCVE/MRE https://stackoverflow.com/help/minimal-reproducible-example,理想情况下您的所有代码都适合单个类。

我没能在不省略代码的情况下使其变得更短以使其运行。

这就是我们要求 MRE 的想法,您应该创建一个全新的程序来隔离问题,在您的情况下,这是:沿某个方向移动形状并继续沿该方向移动。

现在,我可以看到您已经尝试创建它并进行改进,因此我将发布一个示例,说明您未来问题中的预期内容,以便您将来提出更好的问题。

话虽这么说,让我们来回答你的问题。


这是一个不到 100 行代码(不包括注释)的示例,它解决了代码中的以下问题:

  1. 删除while(true)支持 Swing 计时器的声明,以防止阻塞事件调度线程 (EDT)

  2. 将程序放在 EDT 上,请参阅第 2 点这个答案 https://stackoverflow.com/questions/42404270/jcomponent-stops-getting-rendered-once-it-goes-off-the-screen/42404808#42404808

  3. 利用JFrame#pack()方法而不是手动设置它setSize(...)对于两个JFrame and JPanel

  4. 摆脱了“神奇数字”获取指示并使用enum对于这个问题,因此代码更具可读性,因为我们都知道TOP应该将其移至顶部,但我们不知道1应该将其移至顶部。

  5. 利用ShapeAPI来绘制形状JPanel如图所示这个答案 https://stackoverflow.com/questions/41941855/create-the-square-rectangle-triangle-of-java-in-jframe/41944799#41944799

  6. 我还建议使用命名你的方法camelCase以便rungame()变成runGame()因为它更容易阅读,其他方法也是如此。并给它们更有意义的名字,例如hoofd,我不知道那是什么,如果我在没有上下文的情况下单独阅读它,将很难说出它是什么类型的对象。


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class SnakeGame {
    private JFrame frame;
    private Snake snake;
    private JPanel buttonsPane;
    private JButton[] buttons; // Our array of buttons
    private Timer timer;
    private Direction currentDirection;

    // This enum will be used to determine the direction the snake will take.
    private enum Direction {
        TOP, LEFT, BOTTOM, RIGHT
    }

    public static void main(String[] args) {
        // We place our program on the EDT using Java 8 lambda expressions.
        SwingUtilities.invokeLater(() -> new SnakeGame().createAndShowGUI());
    }

    private void createAndShowGUI() {
        frame = new JFrame(getClass().getSimpleName());
        snake = new Snake();
        buttonsPane = new JPanel();
        buttons = new JButton[Direction.values().length];

        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = new JButton(Direction.values()[i].toString()); // We create a JButton with the current value of the direction
            buttons[i].addActionListener(listener); // We set their ActionListeners
            buttonsPane.add(buttons[i]); // And add them to the buttonsPane
        }

        currentDirection = Direction.RIGHT; // We set a default direction
        timer = new Timer(1000, listener); // And start our Swing Timer

        // We add our components and then pack the frame, after that we start the timer.
        frame.add(snake);
        frame.add(buttonsPane, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        timer.start();
    }

    // Our ActionListener for moving the snake
    private ActionListener listener = e -> { // Using Java 8 lambda expressions again
        // We set the current direction using a ternary, if the source of the event is
        // the timer we leave the current direction as is
        // otherwise we set it to the direction from the button clicked
        currentDirection = e.getSource().equals(timer) ? currentDirection : Direction.valueOf(e.getActionCommand());
        snake.move(currentDirection); // And we call the move method
    };

    @SuppressWarnings("serial")
    class Snake extends JPanel {
        private int xPos;
        private int yPos;
        private static final int SPEED = 10; // We set the speed as a constant (10 pixels at a time) in any direction

        // We determine the movement direction
        public void move(Direction direction) {
            switch (direction) {
            case TOP:
                yPos -= SPEED;
                break;
            case LEFT:
                xPos -= SPEED;
                break;
            case BOTTOM:
                yPos += SPEED;
                break;
            case RIGHT:
                xPos += SPEED;
                break;
            }
            this.repaint(); // And repaint the snake
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.DARK_GRAY);
            g2d.fill(new Rectangle2D.Double(xPos, yPos, 10, 10)); // We draw a rectangle using the Shape API
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300); // We set the preferredSize of the JPanel to 300 x 300
        }
    }
}

上面的代码产生以下结果,对于 Java 7 及更低版本,或者如果您不想使用 lambda 表达式或者对您来说太难,请检查此答案的第 2 点,它显示了如何将程序放在 EDT 上没有 lambda 表达式并且这个答案 https://stackoverflow.com/questions/49675729/how-to-make-a-method-that-disables-jbutton/49677070#49677070展示了如何编写ActionListener没有他们也是如此。

这就是一个简单的可运行示例,它是完整的、可验证的、最小的,这就是我们在未来的问题中对您的期望。

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

重绘不会更新屏幕 的相关文章

  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • Grails 3.x bootRun 失败

    我正在尝试在 grails 3 1 11 中运行一个项目 但出现错误 失败 构建失败并出现异常 什么地方出了错 任务 bootRun 执行失败 进程 命令 C Program Files Java jdk1 8 0 111 bin java
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • Spring Data JPA 应用排序、分页以及 where 子句

    我目前正在使用 Spring JPA 并利用此处所述的排序和分页 如何通过Spring data JPA通过排序和可分页查询数据 https stackoverflow com questions 10527124 how to query
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • 使用 pandas to_datetime 时如何定义格式?

    我想根据以下内容绘制结果与时间的关系图testresult csv文件具有以下格式 并且我无法正确定义 TIME 列的数据类型 TIME RESULT 03 24 2016 12 27 11 AM 2 03 24 2016 12 28 41
  • Android Google Cast 通知禁用

    我将 Google Cast 集成到了我的 Android 应用程序中 我的所有内容都是通过带有通知的服务播放的 当我使用 Google Cast 播放媒体时 它会添加自己的通知 是否可以禁用默认的谷歌强制转换通知并仅使用自己的通知 谢谢
  • Firefox 和 IE 在 元素上添加了内边距/边距。和clearfix的奇怪之处

    在很长一段时间里 我在 Firefox 和 IE 中遇到了一些垂直间距问题 我正在使用一个 我的 css 中的选择器将边距应用于某个容器元素内的所有内容 在 Chrome 中工作正常 但是在 FF 和 IE 中 我似乎不知从何而来得到了神秘
  • 在数据库设计中什么时候需要使用一对一关系?

    在数据库设计中什么时候需要使用一对一关系 在我看来 如果两个表是一对一的关系 那么它们可以合并成一个表 这是真的 对大型表进行垂直分区以减少 I O 和缓存需求 将经常查询的列与很少查询的列分开 向生产系统添加列时alter table就是
  • PHP DOM 获取选定的

    假设 HTML 看起来像这样
  • 在 jQuery 中删除或更改 CSS 伪类

    一个足够简单的问题 如此简单 是否可以使用 jQuery 删除或更改 CSS 伪类 或者任何其他与此相关的 Javascript 方法 具体来说 我想摆脱 专注于输入 我无法以任何方式直接更改 CSS 文件 谢谢你的帮助 Buster 我无
  • 干净地销毁System V共享内存段

    我在用shmget shmat and shmctl分别获取和创建共享内存段 将其附加到进程地址空间中并删除它 我想知道进程是否仍然可以使用共享内存段 即使它已被分离并要求使用删除 shmctl id IPC RMID 在一个过程中 我无法
  • 如何从具体类转换为接口类型?

    我正在构建一个多层应用程序 当我将对象从表示层传递到业 务层时 我想将其转换为接口类型 因为业务层不知道表示层的具体类 public ActionResult SubmitSurvey SurveyAnswer answers ISurve
  • 通过 POST 将 JSON 编码的变量从 PHP 传递到 Javascript

    我有一个多维数组 我想将其发送到带有 Javascript 的 PHP 脚本 该脚本解析 JSON 数据并将其绘制在 Google 地图上 我正在尝试使用表单来模拟它
  • 使用 Rails/ActiveRecord 覆盖旧数据库中列的名称或别名

    我正在针对旧数据库编写 Rails 应用程序 此旧数据库中的一个表有一个名为object id 很遗憾object id也是 Ruby 中每个对象的属性 因此当 ActiveRecord 尝试使用这些对象来制定查询时 它使用 Ruby 定义
  • 如何有效地计算 Perl 中覆盖给定范围的范围?

    我有一个大约 30k 范围的数据库 每个范围都作为一对起点和终点给出 12 80 34 60 34 9000 76 743 我想编写一个 Perl 子例程来表示一个范围 不是来自数据库 并返回数据库中完全 包含 给定范围的范围数 例如 如果
  • WCF 数据契约/序列化

    我创建了一个简单的 WCF 应用程序 它公开一个操作 此操作采用复合数据类型作为参数 我没有用 DataContract 属性修饰这个复合数据类型 但这是有效的 我可以在 WSDL 中看到它的架构 现在我的理解是 这个新的自定义类型应该用
  • 更新插入不适用于 updateOnebulkWrite v3.4

    我正在尝试批量写入一些更新 除了更新插入之外的所有内容都正常 我的代码完美地更新了所有项目 并且没有给出任何错误 这里的问题是批量插入updateOne没有更新插入 这是我的代码的未经测试和缩短的示例 因此您可能会发现一些语法错误 希望您明
  • 使用 GenericRecord 在 Avro 中填充嵌套记录的问题

    假设我有以下架构 name Profile type record fields name firstName type string name address type type record name AddressUSRecord f
  • 将数据从 Excel 导出到 Outlook

    我已经用 Excel 起草了一封电子邮件 其中填充了数据表中的信息 单元格 A1 到 A4 包含 嗨 希望你做得好 和消息 等等 A5到H10有一个包含信息的表格 A11到A30有类似 期待您的回复 的电子邮件内容 我只想复制 A1 A4
  • 在 Firebase 群组消息应用中实现已读回执功能

    我想在我的 Firebase 群组消息应用中实现 Seen 功能 您能否建议采取最好 最有效的方法 工作代码将不胜感激 例如 应用程序会显示 已被 6 人看过 or 15 人看过 在群组消息中 这是我的项目 https github com
  • Cesium - 为什么 scene.pickPositionSupported 为 false

    我最终试图在我的房子顶部画一个多边形 我能做到 问题是 在缩小 放大和旋转 或相机移动 时 多边形不会粘在我房子的顶部 我得到了很大的帮助这个答案 https stackoverflow com a 35992537 1735836 所以
  • 有人请解释 Calendar.get(cal.DAY_OF_WEEK) 如何给出正确的输出,而 cal.DAY_OF_WEEK 是默认且未修改的? [复制]

    这个问题在这里已经有答案了 我想知道约会的日子 当我在 cal set year month 1 day 中设置日期时 设置日历字段YEAR MONTH DAY OF MONTH HOUR OF DAY 和 MINUTE 的值 其他字段的先
  • Cloud Functions for Firebase - 创建新用户时写入数据库

    我对 Firebase 和 javascript 语言的 Cloud Functions 非常陌生 我试图在每次创建用户写入数据库时 添加一个函数 这是我的代码 const functions require firebase functi
  • 重绘不会更新屏幕

    我想重新粉刷我的屏幕 到目前为止 它所做的只是在第一个屏幕上显示一个点 即头部应该在的位置 这很好 但是我在代码中写道 我希望每秒将头部向下移动 10 像素 我正在打印头部应该在的位置 并且在命令提示符中显示 y 值确实在增加 然而在我的屏