1

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

4

3 回答 3

6

如果你想在 Swing 中使用动画,推荐使用的类是javax.swing.Timer. 此类允许您定期对 Event Dispatch Thread 执行操作。

于 2012-12-08T17:39:52.333 回答
2

一些一般规则

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

示例解决方案

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

你可以使用 a SwingWorker,但考虑到你要做的就是进入一个无限循环并且它更容易使用SwingUtilities#invokeLater然后实际使用该publish方法,这种方法实际上会更有效。

您也可以使用 a Thread,但最终会遇到与使用 a 相同的问题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 中的Swing 计时器并发以获取更多信息

于 2012-12-08T20:26:54.413 回答
0

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

查看这篇文章以获取更多信息GUI Threading in Java

于 2012-12-08T17:23:36.623 回答