jframejava中的闪烁

jframejava中的闪烁,java,swing,concurrency,java-2d,Java,Swing,Concurrency,Java 2d,大家好,我正在做一个线程来更新JFrame上的一个球,所以我重新绘制了屏幕。。。然后绘制球并更新其位置。。然后再画一次屏幕。。。画出球和相同的循环。。。这是密码 private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) { Thread t = new Thread() { public void run() { while(true) {

大家好,我正在做一个线程来更新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下一样

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


有关Java中的GUI线程的更多信息,请参阅帖子

如果您想在Swing中使用动画,建议使用的类是
javax.Swing.Timer
。此类允许您定期在事件分派线程上执行操作

  • 在SO上发布的消息(在SO上的Swing wiki中链接)

  • 一些一般规则

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

    你有很多选择,这取决于你最终想要实现的目标

    您可以使用
    SwingWorker
    ,但考虑到您要做的就是进入一个无限循环,使用
    SwingUtilities#invokeLater
    然后实际使用
    publish
    方法会更容易,这种方法实际上需要更多的工作

    您也可以使用
    线程
    ,但最终会遇到与使用
    SwingWorker

    simpliset解决方案实际上是一个
    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);
            }
    
        }
    
    }
    

    您可以查看和了解更多信息

    b2和ob变量的类型是什么?我认为问题可能是因为您在EDT(事件调度线程)之外调用SWING代码。在EDT之外调用repaint是可以的(repaint是少数例外之一),但如果b2是swing(或awt)组件,则在EDT之外调用其方法是不可以的。b2变量是公共类Ball extends JApplet的一个实例,它就是Ball本身。。ob变量是jframe对象的引用。。我将其发送到球,以确定帧的高度和宽度,以避免超出边界。。你知道吗。。。当我注释这行时,请重新绘制();球出现了,但是越过了jframe,jframe没有得到预期的更新。。但一旦我加上它。。球消失了!!您不应该在EDT之外处理GUI更新任务。要更快地获得更好的帮助,请发布一个。不,它不起作用。。就好像我在画球,但屏幕上没有重新油漆一样。。。。所以我仍然可以在屏幕上看到球的轨迹。。。。就像我看到了球的位置。。。而且它们不会被删除。。。这不是我想要的..在EDT上调用
    Thread.sleep
    ,因为它会阻塞整个UI。如果你想在SwingYou中制作动画,可以使用
    javax.swing.Timer
    类。你也可以使用SwingWorker。@2012 EndoftheWorld SwingWorker对于这个问题来说是致命的+1对于
    javax.swing.Timer
    ,它方便地封装了睡眠。