i've built a program with a JScrollPane this scrollpane includes another JPanel with null Layout and this panel includes a few other JPanels[I'll name them subpanels] (with some painted things and JLabels) those subpanels are positioned in the panel with the setBounds(int,int,int,int) method (and i don't want to change that)
after searching for a good solution for zooming I've found two options - zoom inside of the paint/paintComponent method (sucks because the painted stuff is changed but not the scale of x,y axis and not the with and height of those subpanels -> my mouselisteners doesn't work (at the wrong place)) - zoom with the viewport of the JScrollPane (doesn't work at all (what i found on google etc.))
so i'm looking for a good solution to zoom in and out of my JPanel
here is some code to imagine what i mean
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class MyAppFrame extends JFrame {
private JScrollPane scroll;
private JPanel nullLayoutPanel;
private JPanel subPanel;
private double zoomFactor;
private double lastScale;
private static Point pressed;
public MyAppFrame(){
setSize(200, 200);
setLocation(50, 50);
zoomFactor = 1.0;
lastScale = 1.0;
nullLayoutPanel = new JPanel(){
//when you try it with the paint method you'll see my problem
//move the rect by dragging it around then
//scroll out or in and try to move the rect
//you'll see that the position of the logical rect doesn't fit with the painted one
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
//g2d.translate(nullLayoutPanel.getWidth()/2, nullLayoutPanel.getHeight()/2);
g2d.scale(zoomFactor, zoomFactor);
//g2d.translate(-nullLayoutPanel.getWidth()/2, -nullLayoutPanel.getHeight()/2);
//super.paint(g2d);
g2d.dispose();
}
@Override
public Dimension getPreferredSize(){
return new Dimension((int)(nullLayoutPanel.getWidth()*zoomFactor), (int)(nullLayoutPanel.getHeight()*zoomFactor));
}
};
nullLayoutPanel.setPreferredSize(new Dimension(400,400));
nullLayoutPanel.setLayout(null);
nullLayoutPanel.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL){
if((.1 * e.getWheelRotation()) > 0 && zoomFactor < 2.0){
zoomFactor += (.1 * e.getWheelRotation());
} else if((.1 * e.getWheelRotation()) < 0 && zoomFactor > 0.1){
zoomFactor += (.1 * e.getWheelRotation());
}
zoomFactor = Math.round(zoomFactor*10.0)/10.0;
zoom(e.getPoint());
}
}
});
scroll = new JScrollPane(nullLayoutPanel);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
getContentPane().add(scroll);
subPanel = new JPanel(){
@Override
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
};
subPanel.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
pressed = e.getPoint();
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
});
subPanel.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent e) {
Point pPoint;
pPoint = subPanel.getLocation();
int x = (int)(pPoint.x - pressed.getX()+e.getX());
int y = (int)(pPoint.y - pressed.getY()+e.getY());
if(x>0&&y>0)
subPanel.setLocation(x,y);
repaint();
}
});
subPanel.setBounds(10, 10, 10, 10);
nullLayoutPanel.add(subPanel);
setVisible(true);
}
public void alignViewPort(Point mousePosition) {
// if the scale didn't change there is nothing we should do
if (zoomFactor != lastScale) {
// compute the factor by that the image zoom has changed
double scaleChange = zoomFactor / lastScale;
// compute the scaled mouse position
Point scaledMousePosition = new Point(
(int)Math.round(mousePosition.x * scaleChange),
(int)Math.round(mousePosition.y * scaleChange)
);
// retrieve the current viewport position
Point viewportPosition = scroll.getViewport().getViewPosition();
// compute the new viewport position
Point newViewportPosition = new Point(
viewportPosition.x + scaledMousePosition.x - mousePosition.x,
viewportPosition.y + scaledMousePosition.y - mousePosition.y
);
// update the viewport position
// IMPORTANT: This call doesn't always update the viewport position. If the call is made twice
// it works correctly. However the screen still "flickers".
scroll.getViewport().setViewPosition(newViewportPosition);
// debug
if (!newViewportPosition.equals(scroll.getViewport().getViewPosition())) {
System.out.println("Error: " + newViewportPosition + " != " + scroll.getViewport().getViewPosition());
}
// remember the last scale
lastScale = zoomFactor;
}
}
public void zoom(Point p){
alignViewPort(p);
nullLayoutPanel.revalidate();
scroll.repaint();
}
/**
* @param args
*/
public static void main(String[] args) {
new MyAppFrame();
}
}
I hope you understand my problem...
edit: changed some code (viewport things)