【问题标题】:Java NetBeans IDE - Animation Flickering in JPanelJava NetBeans IDE - JPanel 中的动画闪烁
【发布时间】:2023-04-10 04:22:02
【问题描述】:

我目前正在学习 NetBeans 中的 Java 动画和图形。

我决定从 JPanel 中的一个简单的球运动开始。

我在解决闪烁问题时遇到了一些问题。我看过很多论坛,但大多数都是针对使用双缓冲的 AWT,但我知道 SWING 组件不需要双缓冲。我试过 - 使用 repaint() 和 .clearRect()

在这 2 个中,我发现使用 .clearRect() 给了我更好的结果,但不是一直无缝的无闪烁动画。所以我想知道是否有更好的方法来消除闪烁。

这是我的代码:

public class NewJFrame extends javax.swing.JFrame {

int x;
int y;
int xspeed = 1;
int yspeed = 1;
int width;
int height;
Graphics g;

    /**
     * Creates new form NewJFrame
     */
    public NewJFrame() {
        initComponents();
    }                             

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
g = jp.getGraphics();
width = jp.getWidth();
height = jp.getHeight();
final Timer timerCHK = new Timer();
timerCHK.schedule(new TimerTask() {
    public void run() {
        move();
        time();

    }
}, 1000, 10);

    }                                        
void time() {
    final Graphics g = jp.getGraphics();
    final Timer timerCHK = new Timer();
    timerCHK.schedule(new TimerTask() {
        public void run() {
            g.clearRect(0, 0, jp.getWidth() - 3, jp.getHeight() - 3);

        }
    }, 1000, 12);
}

void move() {
    x = x + xspeed;
    y = y + yspeed;
    Graphics mk = jp.getGraphics();
    if (x < 0) {
        x = 0;
        xspeed = -xspeed;
    } else if (x > width - 20) {
        x = width - 20;
        xspeed = -xspeed;
    }

    if (y < 0) {
        y = 0;
        yspeed = -yspeed;
    } else if (y == height - 20) {
        y = height - 20;
        yspeed = -yspeed;
    }

    mk.drawOval(x, y, 20, 20);

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

        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }
}

【问题讨论】:

  • 1) Thread.sleep(5); 不要阻塞 EDT(事件调度线程)——当这种情况发生时,GUI 会“冻结”。而不是调用Thread.sleep(n) 实现一个Swing Timer 用于重复任务或SwingWorker 用于长时间运行的任务。有关详细信息,请参阅Concurrency in Swing。 2) 为了尽快获得更好的帮助,请发布SSCCE。 3)g 来自哪里?它有一种“不好的代码气味”。当我看到 SSCCE 时会知道更多。 4) jp.setDoubleBuffered(true); - JComponent 对象默认是双缓冲的。
  • @AndrewThompson 感谢您的回复。我已将我的代码编辑得简短而简单,但我仍然不确定如何将其设为“SSCCE”代码。“g”是图形变量(我现在已将其添加到代码中)。我尝试给出另一个方法 timer() 在 move() 之后 timer() 由我在主代码中使用的相同计时器组成。我仍然在动画中闪烁。
  • “我仍然不确定如何将其设为“SSCCE”代码。”您在理解 S-SC-C-E 的哪个部分有困难?
  • SO上有很多动画例子,你可以试试this example
  • 还有this一个

标签: java swing animation graphics ide


【解决方案1】:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class NewJFrame extends JFrame {

    private JPanel jp;
    private Timer timer;

    public NewJFrame() {
        initComponents();

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        this.setLocationByPlatform(true);
        timer.start();
    }

    public void initComponents() {
        ActionListener al = new ActionListener() {

            public void actionPerformed(ActionEvent evt) {
                jp.repaint();
            }
        };
        timer = new Timer(50,al);

        jp = new JPanel() {

            int x;
            int y;
            int xspeed = 1;
            int yspeed = 1;

            Dimension preferredSize = new Dimension(300, 100);

            @Override
            public Dimension getPreferredSize() {
                return preferredSize;
            }

            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                this.move();
                Graphics2D g2 = (Graphics2D)g;
                g2.setRenderingHint(
                        RenderingHints.KEY_ANTIALIASING, 
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g.drawOval(x, y, 20, 20);
            }

            void move() {
                x = x + xspeed;
                y = y + yspeed;
                if (x < 0) {
                    x = 0;
                    xspeed = -xspeed;
                } else if (x > getWidth() - 20) {
                    x = getWidth() - 20;
                    xspeed = -xspeed;
                }

                if (y < 0) {
                    y = 0;
                    yspeed = -yspeed;
                } else if (y == getHeight() - 20) {
                    y = getHeight() - 20;
                    yspeed = -yspeed;
                }
            }
        };
        jp.setBackground(Color.ORANGE);

        this.add(jp);
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }
}

【讨论】:

  • 对此仍然不清楚。我正在使用带有摆动组件(拖放类型)的 netbeans IDE,您发布的内容与我的 netbeans 屏幕上的内容有些不同。我感谢您耐心回答我的问题。
    注意:我在 Netbeans 的“源”选项卡中的整个代码 - [链接]beetxt.com/2lN 我想知道其中的 paintComponent() {} 和大部分其他东西(不是在这里抱怨..只是问)为什么它不在生成的“自动”或我的代码的任何部分?)
  • 除此之外,您提到的其他内容(例如 paintComponent())在代码中的任何位置都不存在。还有另一件事 - 我只是更改了代码的 ActionEvent 部分,您已将 repaint()方法来测试它的不同方法的工作,但它一直给我“'required: int,java.awt.event.ActionListener found: int,javaapplication8.ActionListner'”错误。格式/一切都是相同的,除了变量名(fff而不是 al) 和要在 ActionEvent() 中完成的代码/函数。
  • 真的很抱歉.. 答案原来是一个愚蠢的拼写错误,通常由 IDE 通知。我写的是 ActionListner 而不是 ActionListener.. "e" 不见了。
【解决方案2】:

这不是一个答案(本身),而是一个扩展评论 - cmets 没有足够的空间

我想了解更多。你能推荐一些基本的教程吗 动画(就像你提到的例子)开始?

不幸的是,没有。几年前我参加了一个简短的 3D 动画课程,并将其中的许多基本原理应用到我的编程中。虽然许多理论对于我们的工作来说是多余的,但理解它们仍然很重要。

您将面临的问题不仅是您需要对动画理论有很好的理解,还需要对 Swing 的内部工作原理和 API 有很好的理解。

在这方面有许多很好的 API 可以帮助您,但您仍然需要了解动画理论才能将它们用于盗版用途。

  • TimingFramwork - 在版本 1 之前我就一直在使用这个 API。我已经围绕它构建了一个合理的代码库,并且发现它非常灵活和有用。最新版本需要一些工作才能运行...
  • Trident - 与 TimingFramework 类似,但比 TimingFramework 更关注组件操作。
  • Universal Tween Engine - 我没用过这个,但我非常有兴趣看看...

Kirill Grouchnikov 在他的Pushing Pixels 网站上发表了一些出色的文章(以支持他的Trident animation 引擎),这可能是两个学科之间的适当折衷。

Kirill 还重点介绍了以下文章(我不得不承认,我还没有读过……;))

使用 Swing 侧更新

对于 Swing 方面,您需要对...有一个很好的理解。

在 Swing 中绘画 - 查看 Painting in AWT and SwingPerforming Custom Painting

这非常非常重要。这是开发人员第一次尝试在 Swing 中执行动画时最常见的误解之一。

您还需要了解Concurrency in Java,尤其是它如何应用于Swing

【讨论】:

  • 非常感谢您的回复。我将查看以上所有链接以进一步学习动画。
  • @halfer 我觉得我写的帖子很好-(谢谢)-您还更正了直接引用:/
  • 好的,好东西:-)
【解决方案3】:

我有一个非常相似的闪烁问题,我用过

contentPane.updateUI();

解决了我所有的问题 如果 updateUI() 解决了您的问题,请告诉我

【讨论】:

  • umm 我应该在哪里实现它?.. 是在 move() 方法之后还是在计时器循环中?如果是定时器循环,延迟应该是多少?
  • UpdateUI 用于通知组件外观发生了变化,这是不适合更新屏幕的方法,也很慢。无效、重新验证和重新绘制(和/或组合)绰绰有余
猜你喜欢
  • 1970-01-01
  • 2012-04-09
  • 2019-03-05
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 2011-12-02
  • 2012-03-12
  • 2011-03-30
相关资源
最近更新 更多