问题
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