This week's book giveaway is in the OCPJP forum. We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line! See this thread for details.
I'm trying to implement a zoom function for my application. I use a JComboBox in which the user sets the desired scaling. Before the drawing canvas is (re)painted in its paintComponent() function, i set the scale of the Graphics2D object to the scale set by the user (line 91 in the code below). Everything is drawn according to the scale so this works fine. However, my problem is that the mouse listener gets messed up when the scale is changed. For example, if I set scale to 200%, a mouse click which would normally be interpreted as hapenning at point (100, 100) is now taken to happen at (200, 200)ar.
The below code is a small program which illustrates my problem.
I tried setting the scale of the Graphics2D object back to 1 at the end of paintComponent function but it did not change anything. I would be really grateful for suggestions from solution(s) to my problem. Maybe I'm even approaching this problem in a completely wrong way and I shouldn't use the scaling to implement the zoom???
Have you tried the AffineTransform class?
If you use transforms, however, it may be a good idea to duplicate the Graphics object; there is a method in Graphics which I think is called create() which does that. The reason is to avoid tiny floating-point errors from accumulating. I have only had that problem with shearing transforms before, but I wouldn't take any chances.
You need to apply the zoomScale to the mouse click coordinates before using them. If zoomScale is 2, then if you have a circle at 100, 100, you draw it at the screen coordinates 200, 200, right? Now, the question is, if you click at 200, 200, where do you want the circle to go? You want it to appear right where you clicked. What coordinates would a circle need to appear at screen coordinates 200, 200? That's right: 100, 100. Therefore you need to divide your mouse coordinates by the zoom factor before using them:
I work a lot with scaling 2D graphics in this way and I often handle the zooming myself, rather than use scaling. What I mean is that I transform the drawing coordinates of the various shapes "manually", rather than scaling the Graphics context.
I generally do this by multiplying or adding to the raw shape coordinates at the time they are drawn. This also enables me to handle panning/dragging as well as zoom.
The reason that I do this is because scaling affects the appearance of the shapes. For example, if you add these two lines to the end of your paintComponent() method:
you will see that the line thickness changes according to the zoom level. Maybe this is not a problem for your application, but for me the lines etc must always be the same thickness on the screen, regardless of the zoom setting.