我需要一些幫助,弄清楚如何在縮放過程中從鼠標事件轉換坐標。。。當縮放因子為1.0時,它可以工作,但當它改變時,不確定算法。。。
當我注釋掉縮放代碼時,我可以在屏幕周圍拖動矩形,但一旦縮放,鼠標坐標就會在應用縮放后出錯
我就是搞不懂坐標轉換碼
package ca.stackoverflow.main;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Demo extends JFrame {
private static final long serialVersionUID = 1L;
public Demo() {
setPreferredSize(new Dimension(640, 480));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JScrollPane scroll = new JScrollPane(new Panel());
add(scroll, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Demo demo = new Demo();
demo.setVisible(true);
}
catch(Throwable e) {
throw new RuntimeException(e);
}
}
});
}
}
class Panel extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
private static final long serialVersionUID = 1L;
private static final double MIN_ZOOM_FACTOR = 0.1;
private static final double MAX_ZOOM_FACTOR = 5.0;
private Color _fillColor;
private Point _startPoint;
private double xOffset;
private double yOffset;
private int xdragOffset;
private int ydragOffset;
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private Rectangle _rectangle;
public Panel() {
setPreferredSize(new Dimension(1000, 1000));
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
_fillColor = Color.WHITE;
_rectangle = new Rectangle(50, 50, 100, 200);
}
@Override public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = new AffineTransform();
if (zoomer) {
double xRel = MouseInfo.getPointerInfo().getLocation().getX() - getLocationOnScreen().getX();
double yRel = MouseInfo.getPointerInfo().getLocation().getY() - getLocationOnScreen().getY();
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * xRel;
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * yRel;
prevZoomFactor = zoomFactor;
zoomer = false;
}
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
g2.transform(at);
g.setColor(_fillColor);
g.fillRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
g.setColor(Color.BLACK);
g.drawRect(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
}
@Override public void mouseMoved(MouseEvent e) {
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
repaint();
}
@Override public void mousePressed(MouseEvent e) {
_startPoint = null;
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_startPoint = e.getPoint();
_fillColor = Color.GREEN;
xdragOffset = _startPoint.x - _rectangle.x;
ydragOffset = _startPoint.y - _rectangle.y;
}
repaint();
}
@Override public void mouseDragged(MouseEvent e) {
if(_startPoint != null) {
int diffX = e.getX() - _startPoint.x;
int diffY = e.getY() - _startPoint.y;
_rectangle.x = _startPoint.x + diffX - xdragOffset;
_rectangle.y = _startPoint.y + diffY - ydragOffset;
}
else {
_fillColor = Color.WHITE;
if(_rectangle.contains(e.getPoint())) {
_fillColor = Color.GREEN;
}
}
repaint();
}
@Override public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
if (e.getWheelRotation() < 0) {
zoomFactor = Math.max(zoomFactor / 1.1, MIN_ZOOM_FACTOR);
}
if (e.getWheelRotation() > 0) {
zoomFactor = Math.min(zoomFactor * 1.1, MAX_ZOOM_FACTOR);
}
repaint();
}
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
}
好吧,這比我最初想的要復雜一些。
“基本”概念是,你需要應用你用來繪制組件的相同
AffineTransformation
_rectangle
所以,我首先創建了一個實例屬性來跟蹤當前的轉換,因為這將得到一點re-used
然后我添加了一個getter
然后我“優化”了你的
paintComponent
,真的。。。一般來說,這是一個非常糟糕的主意,但尤其是在油漆通道內
然后,我修改了
mouseWheelMoved
以在每次更改時計算新的AffineTransformation
現在,每次調用
mouseMoved
,都需要將AffineTransformation
應用于_rectangle
,并檢查它是否存在任何沖突。。。現在,我很想在每次調用
mouseWheelMoved
時創建一個“影子”Shape
,因為其他鼠標事件都需要它Runnable example...
我沒有更新你的
mousePressed
或mouseDragged
方法,我讓你自己去做。我還留下了一些調試代碼,可以在每個繪制過程中繪制“變換的形狀”。這是在轉換Graphics
上下文之前繪制的,所以它應該給您一些指導