JFrame Java 中的闪烁

问题描述 投票:0回答:3

大家好,我正在做一个线程来通过 JFrame 更新球,所以我重新绘制屏幕...然后绘制球更新其位置..然后再次绘制屏幕...绘制球并进行相同的循环.. .这是代码

private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
   Thread t = new Thread()
   {
     public void run()
     {
         while(true)
         {
             repaint();
             b2.update(ob,2);
             b2.paint(ob.getGraphics());

             b2.setT(b2.getT() + 1);
             try {
                 Thread.sleep(50);
             } catch (InterruptedException ex) {
                 System.out.println("Error in Sleeping");
             }

         }
     }
   };

   t.start();
}

但问题是我看不到球...屏幕的油漆总是覆盖球,而球就像在 Jframe 下方 ..

java swing concurrency java-2d
3个回答
6
投票

如果您想在 Swing 中添加动画,推荐使用的类是

javax.swing.Timer
。该类允许您定期对事件调度线程执行操作。


3
投票

一些一般规则

  • Swing 不是线程安全的,您应该只在事件调度线程的上下文中更新 UI 组件。
  • 您无法控制绘制过程,而是由重绘管理器控制。您可以通过调用
    repaint
    来请求更新,但在尝试更新显示时切勿直接调用
    update
    paint
  • 绘制子系统使用的
    Graphics
    上下文是共享资源,不能保证在绘制周期之间相同,您永远不应该维护对它的引用。您也不应该依赖
    JComponent#getGraphics
    的结果,此方法能够返回 null。

示例解决方案

您有多种选择,具体取决于您最终想要实现的目标。

你可以使用

SwingWorker
,但考虑到你要做的就是进入无限循环,使用
SwingUtilities#invokeLater
会更容易,而不是实际使用
publish
方法,因此,这种方法实际上会更多工作。

您也可以使用

Thread
,但最终会遇到与使用
SwingWorker

相同的问题

对于您所提出的,最简单的解决方案实际上是一个

javax.swing.Timer

public class Blinky {

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

    public Blinky() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new BlinkyPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    protected class BlinkyPane extends JPanel {

        private JLabel blinkyLabel;
        private boolean blink = false;

        public BlinkyPane() {
            setLayout(new GridBagLayout());
            blinkyLabel = new JLabel("I'm blinking here");
            blinkyLabel.setBackground(Color.RED);
            add(blinkyLabel);

            Timer timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    blink = !blink;
                    if (blink) {
                        blinkyLabel.setForeground(Color.YELLOW);
                    } else {
                        blinkyLabel.setForeground(Color.BLACK);
                    }
                    blinkyLabel.setOpaque(blink);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 100);
        }

    }

}

您可以查看 Swing TimerSwing 中的并发 了解更多信息


0
投票

如果您在 EDT(事件调度线程)之外访问 GUI 组件,那么您可能会遇到奇怪的问题,相反,如果您在 EDT 中执行长时间运行的任务,那么您也会遇到问题。

查看 this 帖子以了解有关

GUI Threading in Java

的更多信息
© www.soinside.com 2019 - 2024. All rights reserved.