Zoom Box for Area Around Mouse Location on Screen

Zoom box for area around mouse location on screen

I'm sure there are a number of different ways that this could be achieved.

This basically uses a separate component, which acts as the "zoom box". You supply it a component that you want to "zoom" on. It adds a mouse listener so it can monitor mouse motion events and enter and exit events.

These are used to determine when the "popup" window should be shown, where the popup window should be shown and the area that should be "painted".

This uses the "component to be zoomed" paint method to paint a region to of it to a backing buffer, which is then scaled and painted to the "zoom box"...simple

I've not played around with the zoom factor, so there may still be some quirks, but you should get the basic idea...

While I've presented a image to act as the background, this should work on any component

Sample Image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ZoomBoxWindow {

public static void main(String[] args) {
new ZoomBoxWindow();
}

public ZoomBoxWindow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

TestPane pane = new TestPane();
ZoomPane zoomPane = new ZoomPane(pane);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public static class ZoomPane extends JPanel {

protected static final int ZOOM_AREA = 40;

private JComponent parent;
private JWindow popup;

private BufferedImage buffer;

private float zoomLevel = 2f;

public ZoomPane(JComponent parent) {
this.parent = parent;
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
MouseAdapter ma = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
Point pos = e.getLocationOnScreen();
updateBuffer(p);
popup.setLocation(pos.x + 16, pos.y + 16);
repaint();
}

@Override
public void mouseEntered(MouseEvent e) {
popup.setVisible(true);
}

@Override
public void mouseExited(MouseEvent e) {
popup.setVisible(false);
}

};

parent.addMouseListener(ma);
parent.addMouseMotionListener(ma);
}

protected void updateBuffer(Point p) {
int width = Math.round(ZOOM_AREA);
int height = Math.round(ZOOM_AREA);
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
AffineTransform at = new AffineTransform();

int xPos = (ZOOM_AREA / 2) - p.x;
int yPos = (ZOOM_AREA / 2) - p.y;

if (xPos > 0) {
xPos = 0;
}
if (yPos > 0) {
yPos = 0;
}

if ((xPos * -1) + ZOOM_AREA > parent.getWidth()) {
xPos = (parent.getWidth() - ZOOM_AREA) * -1;
}
if ((yPos * -1) + ZOOM_AREA > parent.getHeight()) {
yPos = (parent.getHeight()- ZOOM_AREA) * -1;
}

at.translate(xPos, yPos);
g2d.setTransform(at);
parent.paint(g2d);
g2d.dispose();
}

@Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}

}

public class TestPane extends JPanel {

private BufferedImage img;

public TestPane() {
try {
img = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}

@Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}

}

}

Updated with "screen" version

This version will allow you to display a "zoom window" any where on the screen.

This has a minor issue in the fact that you need to hide the zoom window before you capture the screen, then re-show it.

I might be tempted to change the process so that when the updateBuffer method detected that the mouse position hadn't changed, it updated the buffer and showed the zoom window. When the mouse position changes, it would hide the window again...but that's me ;)

Sample Image

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;

public class GlobalZoomBox {

public static void main(String[] args) {
new GlobalZoomBox();
}

public GlobalZoomBox() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Zoomer zoomer = new Zoomer();
zoomer.setZoomWinodwVisible(true);
}
});
}

public class Zoomer extends JPanel {

protected static final int ZOOM_AREA = 40;

private JWindow popup;

private BufferedImage buffer;
private Robot bot;

private float zoomLevel = 2f;
private Point lastPoint;
private final Timer timer;

public Zoomer() {
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
try {
bot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
timer = new Timer(125, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
}
});
timer.setCoalesce(true);
timer.setInitialDelay(0);
}

public void setZoomWinodwVisible(boolean value) {

if (value && !popup.isVisible()) {

timer.start();
popup.setVisible(true);

} else {

timer.stop();
popup.setVisible(false);

}

}

@Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}

protected void updateBuffer() {
if (bot != null) {
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
if (lastPoint == null || !lastPoint.equals(p)) {
int x = p.x - (ZOOM_AREA / 2);
int y = p.y - (ZOOM_AREA / 2);
popup.setLocation(p.x + 16, p.y + 16);
popup.setVisible(false);
buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
popup.setVisible(true);
lastPoint = p;
repaint();
}
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}

}

}

Updated with "tooltip" style popup

The main problems with the second example is the fact that you need to hide the popup in order to grab a screen shoot. This is done to prevent the popup from begin captured as well. This makes the popup "flash" every time the mouse is moved.

You "could" get around this ensuring the popup is positioned out side the range of the capture, but as you increase the capture area, the popup will move further away from the cursor.

This would, of course, be a great solution for fixed position display (ie, you had a panel fixed on a JFrame instead of a floating box)

This is an additional update that uses a second timer to display the zoom box after the user has stopped moving the mouse.

Sample Image

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;

public class GlobalZoomBox {

public static void main(String[] args) {
new GlobalZoomBox();
}

public GlobalZoomBox() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Zoomer zoomer = new Zoomer();
zoomer.setZoomWinodwVisible(true);
}
});
}

public class Zoomer extends JPanel {

protected static final int ZOOM_AREA = 80;

private JWindow popup;

private BufferedImage buffer;
private Robot bot;

private float zoomLevel = 2f;
private Point lastPoint;
private final Timer timer;
private final Timer popupTimer;

public Zoomer() {
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
try {
bot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
timer = new Timer(125, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateBuffer();
}
});
timer.setCoalesce(true);
timer.setInitialDelay(0);

popupTimer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (lastPoint != null) {
System.out.println("lastPoint = " + lastPoint);
popup.setVisible(false);
Point p = lastPoint;
int x = p.x - (ZOOM_AREA / 2);
int y = p.y - (ZOOM_AREA / 2);
popup.setLocation(p.x + 16, p.y + 16);
buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
repaint();
popup.setVisible(true);
}
}
});
popupTimer.setRepeats(false);
}

public void setZoomWinodwVisible(boolean value) {

if (value && !popup.isVisible()) {

timer.start();
popup.setVisible(true);

} else {

timer.stop();
popup.setVisible(false);

}

}

@Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}

protected void updateBuffer() {
if (bot != null) {
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
if (lastPoint == null || !lastPoint.equals(p)) {
lastPoint = p;
popupTimer.stop();
popup.setVisible(false);
} else {
if (!popup.isVisible()) {
popupTimer.start();
}
}
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}

}

}

Zoom/scale at mouse position

Use the canvas for zoomable content

Zooming and panning elements is very problematic. It can be done but the list of issues is very long. I would never implement such an interface.

Consider using the canvas, via 2D or WebGL to display such content to save your self many many problems.

The first part of the answer is implemented using the canvas. The same interface view is used in the second example that pans and zooms an element.

A simple 2D view.

As you are only panning and zooming then a very simple method can be used.

The example below implements an object called view. This holds the current scale and position (pan)

It provides two function for user interaction.

  • Panning the function view.pan(amount) will pan the view by distance in pixels held by amount.x, amount.y
  • Zooming the function view.scaleAt(at, amount) will scale (zoom in out) the view by amount (a number representing change in scale), at the position held by at.x, at.y in pixels.

In the example the view is applied to the canvas rendering context using view.apply() and a set of random boxes are rendered whenever the view changes.
The panning and zooming is via mouse events

Example using canvas 2D context

Use mouse button drag to pan, wheel to zoom

const ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
const rand = (m = 255, M = m + (m = 0)) => (Math.random() * (M - m) + m) | 0;

const objects = [];
for (let i = 0; i < 100; i++) {
objects.push({x: rand(canvas.width), y: rand(canvas.height),w: rand(40),h: rand(40), col: `rgb(${rand()},${rand()},${rand()})`});
}

requestAnimationFrame(drawCanvas);

const view = (() => {
const matrix = [1, 0, 0, 1, 0, 0]; // current view transform
var m = matrix; // alias
var scale = 1; // current scale
var ctx; // reference to the 2D context
const pos = { x: 0, y: 0 }; // current position of origin
var dirty = true;
const API = {
set context(_ctx) { ctx = _ctx; dirty = true },
apply() {
if (dirty) { this.update() }
ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5])
},
get scale() { return scale },
get position() { return pos },
isDirty() { return dirty },
update() {
dirty = false;
m[3] = m[0] = scale;
m[2] = m[1] = 0;
m[4] = pos.x;
m[5] = pos.y;
},
pan(amount) {
if (dirty) { this.update() }
pos.x += amount.x;
pos.y += amount.y;
dirty = true;
},
scaleAt(at, amount) { // at in screen coords
if (dirty) { this.update() }
scale *= amount;
pos.x = at.x - (at.x - pos.x) * amount;
pos.y = at.y - (at.y - pos.y) * amount;
dirty = true;
},
};
return API;
})();
view.context = ctx;
function drawCanvas() {
if (view.isDirty()) {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);

view.apply(); // set the 2D context transform to the view
for (i = 0; i < objects.length; i++) {
var obj = objects[i];
ctx.fillStyle = obj.col;
ctx.fillRect(obj.x, obj.y, obj.h, obj.h);
}
}
requestAnimationFrame(drawCanvas);
}

canvas.addEventListener("mousemove", mouseEvent, {passive: true});
canvas.addEventListener("mousedown", mouseEvent, {passive: true});
canvas.addEventListener("mouseup", mouseEvent, {passive: true});
canvas.addEventListener("mouseout", mouseEvent, {passive: true});
canvas.addEventListener("wheel", mouseWheelEvent, {passive: false});
const mouse = {x: 0, y: 0, oldX: 0, oldY: 0, button: false};
function mouseEvent(event) {
if (event.type === "mousedown") { mouse.button = true }
if (event.type === "mouseup" || event.type === "mouseout") { mouse.button = false }
mouse.oldX = mouse.x;
mouse.oldY = mouse.y;
mouse.x = event.offsetX;
mouse.y = event.offsetY
if(mouse.button) { // pan
view.pan({x: mouse.x - mouse.oldX, y: mouse.y - mouse.oldY});
}
}
function mouseWheelEvent(event) {
var x = event.offsetX;
var y = event.offsetY;
if (event.deltaY < 0) { view.scaleAt({x, y}, 1.1) }
else { view.scaleAt({x, y}, 1 / 1.1) }
event.preventDefault();
}
body {
background: gainsboro;
margin: 0;
}
canvas {
background: white;
box-shadow: 1px 1px 1px rgba(0, 0, 0, .2);
}
<canvas id="canvas"></canvas>

Zooming graphics based on current mouse position

Too lazy to make the equations right (and most likely would made similar mistake as you... I do not know if it is just me but exactly this easy stuff I cant handle and drives me mad). Instead I am dealing with this kind of tasks as follows (it is much safer from mistakes):

  1. create transform functions between screen and world coordinates

    So your mouse position is in screen coordinates and rendered stuff is in world coordinates. As this is only 2D then it is easy. make function that converts between these two. Your world to screen transform (if I am not overlooking something) is this:

    g.ScaleTransform(_scale, _scale);
    g.TranslateTransform(_translateX, _translateY);

    so:

    screen_x=(world_x*_scale)+_translateX;
    screen_y=(world_y*_scale)+_translateY;

    So the reverse:

    world_x=(screen_x-_translateX)/_scale;
    world_y=(screen_y-_translateY)/_scale;
  2. change of zoom/scale

    The idea is that after zoom/scale change the mouse position should stay the same in world coordinates as before. so remember world coordinates of mouse before change. Then compute from it the screen position after change and the difference put into translation.

Here simple C++ example:

double x0=0.0,y0=0.0,zoom=1.0,mx,my;
//---------------------------------------------------------------------------
void scr2obj(double &ox,double &oy,double sx,double sy)
{
ox=(sx-x0)/zoom;
oy=(sy-y0)/zoom;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
sx=x0+(ox*zoom);
sy=y0+(oy*zoom);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
x0+=mx-mx0;
y0+=my-my0;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y)
{
mx=X; my=Y;
}
//---------------------------------------------------------------------------

the mx,my is actual mouse position in screen coordinates, the x0,y0 is the translation and zoom is the scale.

And here captured GIF animation of this:

example

[edit1] It looks like your gfx objects use transponed matrices

That means the order of transformations is reversed so the equations change a bit... Here your case example in C++:

void scr2obj(double &ox,double &oy,double sx,double sy) 
{
// ox=(sx-x0)/zoom;
// oy=(sy-y0)/zoom;
ox=(sx/zoom)-x0;
oy=(sy/zoom)-y0;
}
//---------------------------------------------------------------------------
void obj2scr(double &sx,double &sy,double ox,double oy)
{
// sx=x0+(ox*zoom);
// sy=y0+(oy*zoom);
sx=(x0+ox)*zoom;
sy=(y0+oy)*zoom;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom/=1.25; // zoom out
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled)
{
double mx0,my0;
scr2obj(mx0,my0,mx,my);
zoom*=1.25; // zoom in
obj2scr(mx0,my0,mx0,my0);
// x0+=mx-mx0;
// y0+=my-my0;
x0+=(mx-mx0)/zoom;
y0+=(my-my0)/zoom;
_redraw=true;
}
//---------------------------------------------------------------------------

Calculate correct cursor position with pan and zoom

Using a TrackBar for the Zoom and two more for the offsets this seems to work:

private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Bitmap bmp = new Bitmap(filename))
{
e.Graphics.ScaleTransform(zoom, zoom);
e.Graphics.DrawImage(bmp, trb_offsetX.Value, trb_offsetY.Value);
}
}

float zoom = 1f;

private void panel1_MouseMove(object sender, MouseEventArgs e)
{

Point mouseLocation = e.Location;
Point imageLocation = new Point((int)((mouseLocation.X / zoom - trb_offsetX.Value)),
(int)((mouseLocation.Y / zoom - trb_offsetY.Value)));

st_mousePos.Text = " " + imageLocation.ToString();

}

private void trackBar1_Scroll(object sender, EventArgs e)
{
zoom = trackBar1.Value;
panel1.Invalidate();
}

I have added the code for the Paint event, so you can see if that's the way your are handling it, too.

performing zoom with mouse wheel programmatically for D3 parallel coordinates plot

i could do what i want by using window.scrollTo(x,y), so that i can zoom and place the screen to mouse position. maybe i was not clear in my question but that what i want.
Thanks,

Make ZoomBox around cursor disappear when JCheckBox unchecked

So,

zoomBoxChkBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if (e.getStateChange() == ItemEvent.SELECTED) {
zoomPane = new ZoomPane(pane, true);
} else {

zoomPane = new ZoomPane(pane, false);
}
}
});

Isn't really doing anything, you're just create a new instance of ZoomPane. Apart from adding a bunch of MouseListeners to the parent component, which could cause you no end of issues.

Instead, I'd add a new method to ZoomPane

public class ZoomPane extends JPanel {

private boolean isAutoDisplayEnabled = false;
//...

public void setShowZoomPopup(boolean show) {
popup.setVisible(show);
isAutoDisplayEnabled = show;
}

This now allows you to control the visibility state of the popup externally.

Now, the isAutoDisplayEnabled flag is simply used to determine if the popup should be displayed when the mouseEntered event is triggered, for example...

MouseAdapter ma = new MouseAdapter() {
//...
@Override
public void mouseEntered(MouseEvent e) {
if (isAutoDisplayEnabled) {
popup.setVisible(true);
}
}

Now your ItemListener can control the state of the popup

zoomBoxChkBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if (e.getStateChange() == ItemEvent.SELECTED) {
zoomPane.setShowZoomPopup(true);
} else {
zoomPane.setShowZoomPopup(false);
}
}
});

You could also add a check to see if the mouse is currently within the bounds of the image pane, so you don't show it needlessly, but I'll leave that to you to try and figure out ;)

the popup is flickering as it is being moved

This is, because every time the popup is displayed, it triggers a mouseExit event, which triggers the popup to be hidden, which then triggers a mouseEnter event and so on and so forth...

This is a slightly different take on the same idea, but, instead of a separate window, this paints the zoom as part of the image pane itself.

This does mean that, if the zoom falls beyond the bounds of the panel, it will be truncated, but I've spent some time so that you can resize the panel larger than the image and the zoom effect will still work

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ZoomBoxWindow {

public static void main(String[] args) {
new ZoomBoxWindow();
}

public ZoomBoxWindow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}


Related Topics



Leave a reply



Submit