Java 在面板内放大和缩小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6543453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Zooming in and zooming out within a panel
提问by aps
I have a Panel in which some 2D objects are moving about. I have overridden paintComponent() as necessary. Now I want to be able to zoom in and zoom out that area. When zooming in, scrollbars will appear by which one can view the entire field by scrolling. While zooming in and out, the 2D objects should increase or decrease in size accordingly. Which Swing component or rather combination of components will help to achieve this?
我有一个面板,其中一些 2D 对象正在移动。我已经根据需要覆盖了paintComponent()。现在我希望能够放大和缩小该区域。放大时,会出现滚动条,通过滚动条可以通过滚动查看整个字段。放大和缩小时,2D 对象的大小应相应增加或减少。哪个 Swing 组件或组件的组合将有助于实现这一目标?
采纳答案by Andreas Holstenson
Easiest way is to modify your panel and introduce a double indicating your zoom level. This double would indicate your scale, where 1 is normal and higher is zoomed in. You can use that double together with Graphics2D
in your paintComponent
.
最简单的方法是修改您的面板并引入一个双倍指示您的缩放级别。这个双精度表示你的比例,其中 1 是正常的,更高的是放大的。你可以Graphics2D
在你的paintComponent
.
Such as:
如:
Graphics2D g2 = (Graphics2D) g;
int w = // real width of canvas
int h = // real height of canvas
// Translate used to make sure scale is centered
g2.translate(w/2, h/2);
g2.scale(scale, scale);
g2.translate(-w/2, -h/2);
For the scrolling, put your panel in a JScrollPane and combine that with a getPreferredSize that also uses your zoom scale. JScrollPane uses the preferred size of the component you put in it. It will show scrollbars if the preferred size exceeds its own size.
对于滚动,将您的面板放在 JScrollPane 中,并将其与同样使用您的缩放比例的 getPreferredSize 结合起来。JScrollPane 使用您放入其中的组件的首选大小。如果首选大小超过其自身大小,它将显示滚动条。
If you change the preferred size of your panel so that the width and height it returns is scaled you should be fine. Basically you can just return something like:
如果您更改面板的首选大小,以便缩放它返回的宽度和高度,您应该没问题。基本上你可以只返回类似的东西:
return new Dimension(w * scale, h * scale)
回答by Thanasis1101
I know this question is old, but I thought I could post my solution in case it could be useful for someone in the future.
我知道这个问题很老,但我想我可以发布我的解决方案,以防将来对某人有用。
So, I created a class that extends JPanel which implements the MouseWheelListener in order to detect when the user rolls the mouse. My class also listens for dragging in order to move the contents when the user clicks and drags.
因此,我创建了一个扩展 JPanel 的类,它实现了 MouseWheelListener 以检测用户何时滚动鼠标。我的班级还侦听拖动以便在用户单击和拖动时移动内容。
Code Explanation
代码说明
First, in the constructor you must set this as the MouseWheelListener
首先,在构造函数中,您必须将其设置为 MouseWheelListener
addMouseWheelListener(this);
For the zoom in and out I used a boolean zoomer
(to indicate when the user rolls with the mouse) and two doubles zoomFactor
(to keep the current factor by which the objects' sizes are multiplied) and prevZoomFactor
(for the previous zoom factor).
对于放大和缩小,我使用了一个布尔值zoomer
(以指示用户何时用鼠标滚动)和两个双精度值zoomFactor
(以保持对象大小乘以的当前因子)和prevZoomFactor
(用于先前的缩放因子)。
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
I also override the paint()
method of the JPanel, in which (before drawing anything) when the user zooms (zoomer
=true) I scale the graphics by the zoomFactor
. Code:
我还覆盖了paint()
JPanel的方法,其中(在绘制任何内容之前)当用户缩放(zoomer
=true)时我按zoomFactor
. 代码:
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if (zoomer) {
AffineTransform at = new AffineTransform();
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2.transform(at);
zoomer = false;
}
// All drawings go here
}
Finally, I override the mouseWheelMoved
method of the MouseWheelListener, in which I increase the zoomFactor
(if the user rolls up) or decrease the zoomFactor
(if the user rolls down). Code:
最后,我覆盖了mouseWheelMoved
MouseWheelListener的方法,在该方法中我增加了zoomFactor
(如果用户向上滚动)或减少了zoomFactor
(如果用户向下滚动)。代码:
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
//Zoom in
if (e.getWheelRotation() < 0) {
zoomFactor *= 1.1;
repaint();
}
//Zoom out
if (e.getWheelRotation() > 0) {
zoomFactor /= 1.1;
repaint();
}
}
Working Example
工作示例
If you also want to use the drag function and want to zoom according to the position of the mouse, you can use the class below, which gets a BufferedImage as a parameter in the constructor in order to display something on screen.
如果您还想使用拖动功能并希望根据鼠标的位置进行缩放,您可以使用下面的类,它在构造函数中获取一个 BufferedImage 作为参数,以便在屏幕上显示某些内容。
I have also uploaded a project on GitHub called Zoomable-Java-Panelin which there is a functional example of what I showed above, which you can test and see how it can be implemented into a project.
我还在 GitHub 上上传了一个名为Zoomable-Java-Panel 的项目,其中有我上面展示的功能示例,您可以测试并查看如何将其实现到项目中。
package zoomable.panel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
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 java.awt.image.BufferedImage;
import javax.swing.JPanel;
/**
*
* @author Thanasis1101
* @version 1.0
*/
public class MainPanel extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
private final BufferedImage image;
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private boolean dragger;
private boolean released;
private double xOffset = 0;
private double yOffset = 0;
private int xDiff;
private int yDiff;
private Point startPoint;
public MainPanel(BufferedImage image) {
this.image = image;
initComponent();
}
private void initComponent() {
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
}
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if (zoomer) {
AffineTransform at = new AffineTransform();
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;
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2.transform(at);
zoomer = false;
}
if (dragger) {
AffineTransform at = new AffineTransform();
at.translate(xOffset + xDiff, yOffset + yDiff);
at.scale(zoomFactor, zoomFactor);
g2.transform(at);
if (released) {
xOffset += xDiff;
yOffset += yDiff;
dragger = false;
}
}
// All drawings go here
g2.drawImage(image, 0, 0, this);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoomer = true;
//Zoom in
if (e.getWheelRotation() < 0) {
zoomFactor *= 1.1;
repaint();
}
//Zoom out
if (e.getWheelRotation() > 0) {
zoomFactor /= 1.1;
repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
Point curPoint = e.getLocationOnScreen();
xDiff = curPoint.x - startPoint.x;
yDiff = curPoint.y - startPoint.y;
dragger = true;
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
released = false;
startPoint = MouseInfo.getPointerInfo().getLocation();
}
@Override
public void mouseReleased(MouseEvent e) {
released = true;
repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}