0

我正在尝试从代码中的 run() 调用 repaint 方法。如果我从 MouseDragged 或 MouseMoved repaint() 它工作正常。但我需要从 run() 执行此操作。以下代码不会从 run() 调用 repaint 方法。

我是 JAVA 的新手。任何人都可以修复代码并粘贴代码吗?请原谅任何愚蠢的错误。:)。顺便说一句,我看到 SwingUtilities.invokelater 可以解决这个问题。但我不知道该怎么做。请修复代码。

提前致谢。

import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;

public class Tester {

public static int x,y;
public static void main(String[] args) {
    x = 10; y= 10;
    Draw d = new Draw();
    new Thread(d).start();
}


public static class Draw extends JFrame implements Runnable,MouseMotionListener
{

    public Draw()
    {
        super("Title");
        setSize(500,500);
        addMouseMotionListener(this);
        setVisible(true);
    }


    @Override
    public void run() {
        for(int i = 0 ; i < 10 ; i++)
        {   
            System.out.println("Multithreaded");
            repaint();
        }

    }

    @Override
    public void mouseDragged(MouseEvent e) {

    }

    @Override
    public void mouseMoved(MouseEvent e) {


    }

    public void paint(Graphics g)
    {
        System.out.println("repaint called");
    }

}


}
4

2 回答 2

2

Swing 员工使用被动重绘引擎。也就是说,它只会在需要时更新。它还经过优化,RepaintManager可以将多次重绘合并到它认为需要的尽可能少的重绘事件。

这意味着您可以请求 a repaint,但不能保证何时或是否会发生重绘。

这主要是为了性能优化。

查看AWT 和 Swing 中的绘画以了解更多详细信息。

由于它的性质,repaint是线程安全的。 repaint要求将RepaintManager绘制事件发布到事件队列中。这个队列是由 Event Dispatching Thread 处理的,也就是说,你不必repaint自己与 EDT 同步。

下面的例子演示了这个想法。它提供了一个简单的滑块来重置绘制计数器并设置repaint请求之间的延迟。

线程延迟0毫秒...

在此处输入图像描述

线程延迟2秒

在此处输入图像描述

如你看到的。在 0 毫秒(这实际上是您在循环中所做的)时,实际绘制的数量与重新绘制请求的数量不匹配,但是在 2 秒的延迟时,实际绘制和绘制请求几乎相等(额外的一个来自我认为滑块所做的重绘)。

事实上,在我的测试中,大约 100 毫秒,我能够让它几乎相等。我什至尝试了 5 毫秒并让它保持平衡。

实际油漆在做什么以及 EDT 上的负载也会影响这些结果......

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class RepaintTest {

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

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int paintRequests;
        private int paints;
        private int delay = 0;

        public TestPane() {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        paintRequests++;
                        try {
                            Thread.sleep(delay);
                        } catch (InterruptedException exp) {
                        }
                        System.out.println("tick");
                        repaint();
                    }
                }
            });
            t.setDaemon(true);
            setLayout(new BorderLayout());
            final JSlider slider = new JSlider();
            slider.setMinimum(0);
            slider.setMaximum(2000);
            slider.setPaintTicks(true);
            slider.setMajorTickSpacing(100);
            slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    delay = slider.getValue();
                    paintRequests = 0;
                    paints = 0;
                }
            });
            slider.setValue(0);
            add(slider, BorderLayout.SOUTH);
            t.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            paints++;
            String text = "Paints = " + paints + "; Paint Requests = " + paintRequests;
            Graphics2D g2d = (Graphics2D) g.create();
            FontMetrics fm = g2d.getFontMetrics();
            int x = (getWidth() - fm.stringWidth(text)) / 2;
            int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
            g2d.drawString(text, x, y);
            g2d.dispose();
        }

    }
}
于 2013-09-01T05:50:06.627 回答
0

尝试实现ActionListener,然后添加这段代码:

import javax.swing.Timer;
private final int DELAY = 60;
private Timer t;
public Draw() {
    //your code
    t = new Timer(DELAY, this);
    t.start();
}
//implemented method
@Override
public void actionPerformed(ActionEvent e) {
    repaint();
}

非常不言自明,actionPerformed方法中的任何内容都会每DELAY毫秒调用一次。

于 2013-08-31T17:45:17.123 回答