简体   繁体   中英

Trying to repaint the Gui from run

I'm trying to call the repaint method from the run() in the code. If I repaint() from the MouseDragged or MouseMoved It works fine. But I need to do it from the run().The following code does not make a call to repaint method from run().

I'm new in JAVA. can anyone fix the code and paste the code? please excuse any silly mistakes. :). BTW i saw SwingUtilities.invokelater may fix this. but i don't know how to do that. please fix the code.

Thanks in advance.

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");
    }

}


}

Swing employees a passive repaint engine. That is, it will only update when it is required to. The RepaintManager is also optimised to consolidate multiple repaints down to as few repaint events as it thinks is required.

This means that you can make a request for a repaint , but there is no guarantee to when or if that repaint will occur.

This is done mostly for performance optimisation.

Check out Painting in AWT and Swing for more details.

Because of it's nature, repaint is thread safe. repaint asks the RepaintManager to post a paint event onto the event queue. This queue is the processed by the Event Dispatching Thread, meaning, you don't have to synchronise repaint with the EDT yourself.

The following example demonstrates that idea. It provides a simple slider which resets the paint counters and sets the delay between repaint requests.

Thread delay of 0 milliseconds...

在此输入图像描述

Thread delay of 2 seconds

在此输入图像描述

As you can see. At 0 milliseconds (which is effectively what you are doing in you loop), the number of actual paints no where matches the number of repaint requests, but at a delay of 2 seconds, the actual paints and the paint requests are almost equal (the extra one comes from the repaint made by the slider I think).

In fact, in my testing, at about 100 milliseconds, I was able to get it to just about equal out. I even tried 5 milliseconds and got it to balance.

What the actual paint is doing and the load on the EDT will also effect these results...

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();
        }

    }
}

Try implementing ActionListener , then add this bit of code:

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();
}

Pretty self explanatory, whatever is in the actionPerformed method is called every DELAY milliseconds.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM