Issue with addMouseMotionListener getting wrong coordinates

筅森魡賤 提交于 2019-12-12 04:46:09

问题


I borrowed the class below to make a selection area tool for a project. But it has a issue when I try to make a selection when the content is not aligned at top-left, it get my mouse coordinates related to the ScrollPane, but draws over the image - See this SS for better understanding:

sscce:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.image.*;

import javax.swing.*;

/** Getting a Rectangle of interest on the screen.
Requires the MotivatedEndUser API - sold separately. */
public class ScreenCaptureRectangle {

    Rectangle captureRect;

    ScreenCaptureRectangle(final BufferedImage screen) {
        final BufferedImage screenCopy = new BufferedImage(screen.getWidth(), screen.getHeight(), screen.getType());
        final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
        JScrollPane screenScroll = new JScrollPane(screenLabel);

        screenScroll.setPreferredSize(new Dimension((int)(screen.getWidth()*2), (int)(screen.getHeight()*2)));

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(screenScroll, BorderLayout.CENTER);

        final JLabel selectionLabel = new JLabel("Drag a rectangle in the screen shot!");
        panel.add(selectionLabel, BorderLayout.SOUTH);

        repaint(screen, screenCopy);
        screenLabel.repaint();

        screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

            Point start = new Point();

            @Override
            public void mouseMoved(MouseEvent me) {
                start = me.getPoint();
                repaint(screen, screenCopy);
                selectionLabel.setText("Start Point: " + start);
                screenLabel.repaint();
            }

            @Override
            public void mouseDragged(MouseEvent me) {
                Point end = me.getPoint();
                captureRect = new Rectangle(start, new Dimension(end.x-start.x, end.y-start.y));
                repaint(screen, screenCopy);
                screenLabel.repaint();
                selectionLabel.setText("Rectangle: " + captureRect);
            }
        });

        JOptionPane.showMessageDialog(null, panel);

        System.out.println("Rectangle of interest: " + captureRect);
    }

    public void repaint(BufferedImage orig, BufferedImage copy) {
        Graphics2D g = copy.createGraphics();
        g.drawImage(orig,0,0, null);
        if (captureRect!=null) {
            g.setColor(Color.RED);
            g.draw(captureRect);
            g.setColor(new Color(255,255,255,150));
            g.fill(captureRect);
        }
        g.dispose();
    }

    public static void main(String[] args) throws Exception {
        Robot robot = new Robot();
        final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        final BufferedImage screen = robot.createScreenCapture(new Rectangle(300,0,300,300));

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ScreenCaptureRectangle(screen);
            }
        });
    }
}

回答1:


I think you have problems because you are attempting to center the image in the panel.

The easiest solution is to make sure the image is painted from the top/left of the panel:

    final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
    screenLabel.setHorizontalAlignment(JLabel.LEFT);
    screenLabel.setVerticalAlignment(JLabel.TOP);



回答2:


Basically, what's happening, is you are drawing directly to the image surface (which is held by the JLabel), so while, you drag at 2x2x36x36 on the screen, this then draws on the rectangle RELATIVE to the image itself

So even though the image is centered within the context of the JLabel, you are still rendering to the local context of the image (0x0), hence the disconnection between the two.

Depending on what it is you want to achieve, you change the way the painting works and take more direct control, for example...

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DrawimgExample {

    public static void main(String[] args) {
        try {
            Robot robot = new Robot();
            final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

            final BufferedImage screen = robot.createScreenCapture(new Rectangle(300, 0, 300, 300));
            new DrawimgExample(screen);
        } catch (AWTException exp) {
            exp.printStackTrace();
        }
    }

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new DrawingPane(screen));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class DrawingPane extends JPanel {

        private BufferedImage img;
        private Rectangle drawRect;

        public DrawingPane(BufferedImage img) {
            this.img = img;

            MouseAdapter mouseHandler = new MouseAdapter() {

                private Point startPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    startPoint = e.getPoint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point endPoint = e.getPoint();

                    int startX = Math.min(startPoint.x, endPoint.x);
                    int startY = Math.min(startPoint.y, endPoint.y);

                    int width = Math.max(startPoint.x, endPoint.x) - startX;
                    int height = Math.max(startPoint.y, endPoint.y) - startY;

                    drawRect = new Rectangle(
                            startX,
                            startY,
                            width,
                            height
                    );
                    repaint();
                }

            };

            addMouseListener(mouseHandler);
            addMouseMotionListener(mouseHandler);
        }

        @Override
        public Dimension getPreferredSize() {
            return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - img.getWidth()) / 2;
            int y = (getHeight() - img.getHeight()) / 2;
            g2d.drawImage(img, x, y, this);
            if (drawRect != null) {
                g2d.setColor(Color.RED);
                g2d.draw(drawRect);
                g2d.setColor(new Color(255, 255, 255, 150));
                g2d.fill(drawRect);
            }
            g2d.dispose();
        }
    }

}

Having said that, where possible, you should avoid painting images directly, as JLabel already does a good job, but sometimes, if it doesn't meet your needs, you might need to take more direct control



来源:https://stackoverflow.com/questions/24420761/issue-with-addmousemotionlistener-getting-wrong-coordinates

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