Zoom Help

Hello, I’m trying to do some zooming on some components in Swing and images. This is what I have done so far and it does not work…

I have created a subclass of JLabel and overridden the paintComponent method to display an image. I then have a mouse listener so whenever the user clicks, it’ll zoom in.
This does not work at all. I’ve been trying many examples from these and the Sun forums. Nothing works.

You can change the tank.gif picture to anything that suits your desires.

Here is my code: the subclass and main driver class…a look at it would be most helpful!


package drivers;

import interfaces.ZoomLabel;

import javax.swing.JFrame;

import main.ExitListener;

public class ZoomDriver
{

	/**
	 * @param args
	 */
	public static void main ( String[] args )
	{
		JFrame frame = new JFrame("Zoom Test");
		

		frame.add(new ZoomLabel());
		frame.setSize(400, 400);
		frame.setLocation(0, 0);
		frame.addWindowListener(new ExitListener());
		frame.setVisible(true);
	}

}



package interfaces;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;

import javax.swing.JLabel;

import main.ImageUtilities;

public class ZoomLabel extends JLabel implements MouseListener
{
	private AffineTransform tx=new AffineTransform();
	private AffineTransformOp op=new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
	private BufferedImage image;
	
	public ZoomLabel()
	{
		image = ImageUtilities.getBufferedImage("tank.gif", this);
		addMouseListener(this);
	}
	
	
	public void paintComponent(Graphics g)
	{
	          Graphics2D g2d = (Graphics2D)g;
	          g2d.drawImage(image,op,100,100);
	}

	public void mouseClicked ( MouseEvent e )
	{
		
	}

	public void mouseEntered ( MouseEvent arg0 )
	{
	}

	public void mouseExited ( MouseEvent arg0 )
	{
	}

	public void mousePressed ( MouseEvent e )
	{
		System.out.println("clicking");
		tx = AffineTransform.getTranslateInstance(e.getX(),e.getY());
		tx.scale(.5, .5);
		tx.translate(-e.getX(),-e.getY());
		op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
	}

	public void mouseReleased ( MouseEvent arg0 )
	{
	}
}



Thank you very much!

Edit:

Whoops, and the ImageUtilities class…


package main;
import java.awt.*;
import java.awt.image.*;

/** A class that simplifies a few common image operations, in
 *  particular creating a BufferedImage from an image file, and
 *  using MediaTracker to wait until an image or several images are
 *  done loading. 1998 Marty Hall, http://www.apl.jhu.edu/~hall/java/
 */

public class ImageUtilities {

  /** Create Image from a file, then turn that into a BufferedImage.
   */

  public static BufferedImage getBufferedImage(String imageFile,
                                               Component c) {
    Image image = c.getToolkit().getImage(imageFile);
    waitForImage(image, c);
    BufferedImage bufferedImage =
      new BufferedImage(image.getWidth(c), image.getHeight(c),
                        BufferedImage.TYPE_4BYTE_ABGR );
    Graphics2D g2d = bufferedImage.createGraphics();
    g2d.drawImage(image, 0, 0, c);
    return(bufferedImage);
  }
  
  

  /** Take an Image associated with a file, and wait until it is
   *  done loading. Just a simple application of MediaTracker.
   *  If you are loading multiple images, don't use this
   *  consecutive times; instead use the version that takes
   *  an array of images.
   */

  public static boolean waitForImage(Image image, Component c) {
    MediaTracker tracker = new MediaTracker(c);
    tracker.addImage(image, 0);
    try {
      tracker.waitForAll();
    } catch(InterruptedException ie) {}
    return(!tracker.isErrorAny());
  }

  /** Take some Images associated with files, and wait until they
   *  are done loading. Just a simple application of MediaTracker.
   */

  public static boolean waitForImages(Image[] images, Component c) {
    MediaTracker tracker = new MediaTracker(c);
    for(int i=0; i<images.length; i++)
      tracker.addImage(images[i], 0);
    try {
      tracker.waitForAll();
    } catch(InterruptedException ie) {}
    return(!tracker.isErrorAny());
  }
}


Hi,

I tried your code and quickly found that you are not calling repaint() in your mousePressed method, that’s why nothing seems to change.

As for getting the AffineTransform to do what you want, well that’s hard :stuck_out_tongue: I usually read the docs (http://java.sun.com/javase/6/docs/api/index.html) about it again and again and do trial and error until it works out.

I hope that helps :slight_smile:
Keith

Hey,

Thanks a lot - I figured paintComponent would of taken care of it but I guess not.

It now works and I get to play around with the way I want it to work. I was just trying to initially get something to happen haha.

THANKS!

Alright, new problem!

Let’s say I have a JLabel and I am drawing rectangles on this, which, will then be zoomed. It doesn’t seem to be working too well with updating the location of the rectangles. I can get them to zoom fine BUT I’d like to be able to click on them to get their new coord.'s after they were transformed. This doesn’t work at all for me! I’ve been playing around with it, but alas, it just seems to do crazy things.

I wrote the following up to try and make what I desire, maybe someone can catch what I’m messing up. As of right now, it doesn’t zoom properly because I’ve been playing around with it.

Thanks again!

Driver class:



import javax.swing.JFrame;

//import main.ExitListener;

public class RectangleDriver
{

	/**
	 * @param args
	 */
	public static void main ( String[] args )
	{
		JFrame frame = new JFrame("Zoom Test");
		

		frame.add(new RectangleTest());
		
		frame.setSize(400, 400);
		frame.setLocation(0, 0);
		//frame.addWindowListener(new ExitListener());
		frame.setVisible(true);
	}

}


This is the zooming label…


import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.util.ArrayList;

import javax.swing.JLabel;


public class RectangleTest extends JLabel implements MouseListener, MouseWheelListener
{
		 private ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
	
	 	private AffineTransform tx=new AffineTransform();
	 	private AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
	 	private double currentScale = 1;
	 	
	 	public RectangleTest()
		{
		
			rectList.add(new Rectangle(50, 50, 20, 20));
			rectList.add(new Rectangle(20, 100, 20, 20));
			
			addMouseListener(this);
			addMouseWheelListener(this);
			
		}
	 	
	 	
	 	public void paintComponent(Graphics g)
	 	{
	 	          Graphics2D g2d = (Graphics2D)g;
	 	          g2d.setTransform(tx);
	 	          
	 	          for(int i = 0;i<rectList.size();i++)
	 	          {
	 	        	  //Get the new bounds of the shape
	 	        	  Shape shape = tx.createTransformedShape(rectList.get(i));
	 	        	  //Set them
	 	        	  rectList.get(i).setBounds(shape.getBounds());
	 	        	  //Draw the new bounds
	 	        	  g2d.draw(rectList.get(i));
	 	        	  
	 	          }
	 	}

	 	//Tests to see if we clicked on a rectangle.
	 	public void mouseClicked ( MouseEvent e )
	 	{
	 		for(int i = 0;i<rectList.size();i++)
	 		{
	 			if(rectList.get(i).contains(e.getPoint()))
	 			{
	 				System.out.println("You clicked on a rect! : " + i);
	 			}
	 		}
	 		
	 	}

	 	public void mouseEntered ( MouseEvent arg0 )
	 	{
	 	}

	 	public void mouseExited ( MouseEvent arg0 )
	 	{
	 	}

	 	public void mousePressed ( MouseEvent e )
	 	{
	 		
	 	}

	 	public void mouseReleased ( MouseEvent arg0 )
	 	{
	 	}


	 	//Zooms in and out to a min and max.
	 	public void mouseWheelMoved ( MouseWheelEvent e )
	 	{
	 		if(e.getWheelRotation() >= 1)
	 		{
	 			currentScale += .1;
	 			if(currentScale > 1)
	 				currentScale = 1;
	 		}
	 		else
	 		{
	 			currentScale -= .1;
	 			if(currentScale < .01)
	 				currentScale = .01;
	 		}
	 		tx = AffineTransform.getTranslateInstance(100, 100);
	 		tx.scale(currentScale, currentScale);
	 		tx.translate(-100, -100);
	 		op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
	 		repaint();
	 	}
	
}

Thanks for any help!

So I’ve been playing around with this for a couple of days. What I have now, which works, but is not practical, is a underlying grid that is transformed when the user zooms in and out. The objects move just fine on the screen. No problem.

The problem is that when the user zooms in/out, I have it so the grid does a new transformation of itself so it is correct according to the zoom. If the grid is big, say, 400 x 400, it freezes for a second and this is unacceptable.

My next solution is to somehow calculate where my mouse pointer clicked based on what the transformation is at the moment. Basically, I want to dynamically generate the location of the grid where I am (without actually having a grid). Then I can put this into a list that the program can move the object too. Let me see if I can explain it a bit better, I tried to program it, but I have failed miserably.

Grid width and height at normal view: 20,20. The user zooms out. So then the user clicks in the right hand corner. Let’s say, this represents grid location 4000,4000, but on the user screen the actual coordinate is say 800x600. It needs to somehow get to 4000,4000 from 800x600 based on the current size of the grid’s elements (which may be (x,y,2,2) at this point). When the user zooms all the way in, and clicks in the corner once more, the grid element would in fact be: 800,600,20,20. The only way I can get a coordinate larger then my screen resolution is if I actually draw the grid and do the transformations on it.

Ok, I don’t think I explained it well enough so feel free to ask any questions. Right now I do not have any useful code to post because I haven’t got anywhere productive besides with the inefficient grid.

[Though I did just think of this. If I do a transformation of 1 item on the underlying grid to see how much it changed, ie: it was (10,10,20,20) and then went down to (5,5,10,10). I can then loop through the rest of them and just apply the new change without having to do n transformations. However, I am not sure how exactly the transform works code wise. I also thought of putting the transformation on its own thread that is always created so I can just pass it the transformation to do but I don’t think that’d work too well.]

Ok, its late, I’ve been working on this for 5 hours and its time for bed and that means I tend to ramble.

Here’s a little picture of my problem:
www.tempestseason.net/images/transform.JPG

I’ll try to post the code that I have with that tomorrow, but it uses a bunch of custom stuff so I’ll have to rewrite it.

Thanks for any help.