Swing: How to reduce the response time of MouseInputAdapter?

泄露秘密 提交于 2021-02-11 06:59:40

问题


I've made a tool which could allow user to draw on screenshot.Here is my code:

package GUI.Views;

import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

public class Canvas extends JPanel {
    public static int radius = 5;
    public class DrawPointListener extends MouseInputAdapter{
        private void draw(Point p, int radius){
            Graphics2D g2 = (Graphics2D)getGraphics();
            int x = (int)p.getX() - radius/2;
            int y = (int)p.getY() - radius/2;
            g2.fillOval(x, y, radius, radius);
        }

        @Override
        public void mousePressed(MouseEvent e) {
            draw(e.getPoint(), radius);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            draw(e.getPoint(), radius);
        }
    }

    private BufferedImage screenShot;

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(this.screenShot, 0, 0, null);
    }


    public Canvas() {
        this.setVisible(true);
        this.screenShot = getScreenShot();
        this.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));

        DrawPointListener drawListener = new DrawPointListener();

        this.addMouseListener(drawListener);
        this.addMouseMotionListener(drawListener);
    }

    private BufferedImage getScreenShot() {
        try {
            return new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));

        } catch (AWTException e) {
            System.out.println("Error");
            return null;
        }
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        Canvas canvas = new Canvas();
        f.setUndecorated(true);
        f.add(canvas);
        f.setExtendedState(JFrame.MAXIMIZED_BOTH);
        f.setVisible(true);
    }
}

Code worked fine when you try to "draw" on the screen slowly, but when you move your mouse quickly, you would see those points are not consecutive, like this:

I think that because there is a time interval of Listener.How could I improve it?


回答1:


You can't change the time interval of the listener. You are NOT guaranteed to generate an event for every pixel.

So instead of drawing a single point, you need to draw a line between the current and previous point.

Something like:

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;

class DrawingPanel extends JPanel
{
    private ArrayList<ArrayList<Point>> previous = new ArrayList<ArrayList<Point>>();
    private ArrayList<Point> current = new ArrayList<Point>();
    private BasicStroke basicStroke;

    public DrawingPanel(int strokeSize)
    {
        basicStroke = new BasicStroke(strokeSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);

        MouseAdapter ma = new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent e)
            {
                current.add( new Point(e.getX(), e.getY()) );
            }

            @Override
            public void mouseDragged(MouseEvent e)
            {
                current.add( new Point(e.getX(), e.getY()) );
                repaint();
            }

            @Override
            public void mouseReleased(MouseEvent e)
            {
                if (current.size() > 1)
                {
                    previous.add( current );
                }

                current = new ArrayList<Point>();
            }
        };

        addMouseMotionListener( ma );
        addMouseListener( ma );
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;
        g2.setStroke( basicStroke );

        //  Paint lines from previous drags

        for (int i = 0; i < previous.size(); i++)
        {
            drawLines(g, previous.get(i));
        }

        //  Paint line from current drag

        drawLines(g, current);
    }

    private void drawLines(Graphics g, ArrayList<Point> points)
    {
        for (int i = 0; i < points.size() - 1; i++)
        {
            int x = (int) points.get(i).getX();
            int y = (int) points.get(i).getY();
            int x2 = (int) points.get(i + 1).getX();
            int y2 = (int) points.get(i + 1).getY();
            g.drawLine(x, y, x2, y2);
        }
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("Drawing Panel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new DrawingPanel(15));
        frame.setSize(400, 400);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}


来源:https://stackoverflow.com/questions/65327201/swing-how-to-reduce-the-response-time-of-mouseinputadapter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!