Swing: как сократить время отклика MouseInputAdapter?

#java #swing

#java #swing

Вопрос:

Я создал инструмент, который может позволить пользователю рисовать на скриншоте.Вот мой код:

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

Код работал нормально, когда вы пытались "draw" медленно перемещать курсор по экрану, но когда вы быстро перемещаете мышь, вы увидите, что эти точки не являются последовательными, например:

введите описание изображения здесь

Я думаю, потому что существует интервал времени Listener .Как я мог бы это улучшить?

Комментарии:

1. Вы не можете изменить временной интервал прослушивателя. Вы НЕ гарантированно генерируете событие для каждого пикселя. Поэтому вместо рисования одной точки вам нужно провести линию между текущей и предыдущей точками.

2. @camickr Спасибо за совет. Я попробую это.

Ответ №1:

Вы не можете изменить временной интервал прослушивателя. Вы НЕ гарантированно генерируете событие для каждого пикселя.

Поэтому вместо рисования одной точки вам нужно провести линию между текущей и предыдущей точками.

Что-то вроде:

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

Комментарии:

1. Спасибо за помощь. Я мало что знаю о Java. paintComponent будет обновляться, когда я буду рисовать на этой JPanel. Будет ли это медленно, когда размер previous слишком велик?

2. Ответ на подобный вопрос — попробуйте! Если вы считаете, что есть проблема, вы можете ознакомиться с пользовательскими подходами к рисованию . Затем решите, какой подход лучше для вас, исходя из ваших требований.