Retain relative mouse position while resizing a JPanel in a JScrollPane
I'm resizing a JPanel inside of a JScrollPane, and I want to make sure that the point on the JPanel where my mouse is currently located retains its position with respect to the JScrollPane after the resize (like Google maps does when you zoom in/out).
I find the mouse position on the JPanel, which lets me deal with the viewport being at various positions. I multiply it by the zoom factor so I know where the point will be after scaling. I then subtract the position of the mouse on the ScrollPane so that I know where the point was with respect to the viewable area. I'm doing something wrong however, and I just can't see what.
Example Code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Test
{
public static void main(String[] in)
{
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Test();
}
});
}
public Test()
{
final JFrame frame = new JFrame();
final ScalablePanel child = new ScalablePanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(child, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ScalablePanel
extends JScrollPane
implements MouseWheelListener
{
final double ZOOM_IN_FACTOR = 1.1;
final double ZOOM_OUT_FACTOR = 0.9;
final JPanel zoomPanel = new JPanel();
public ScalablePanel()
{
final javax.swing.JLabel marker = new javax.swing.JLabel("Testing the mouse position on zoom");
marker.setHorizontalAlignment(javax.swing.JLabel.CENTER);
zoomPanel.setLayout(new BorderLayout());
zoomPanel.add(marker,BorderLayout.CENTER);
getViewport().setView(zoomPanel);
setPreferredSize(new Dimension(300,300));
addMouseWheelListener(this);
}
public void mouseWheelMoved(final MouseWheelEvent e)
{
if (e.isControlDown())
{
if (e.getWheelRotation() < 0)
zoomIn(e);
else
zoomOut(e);
e.consume();
}
}
public void zoomIn(final MouseWheelEvent e)
{
// Get the mouse position with respect to the zoomPanel
final Point pointOnZoomPanel = SwingUtilities.convertPoint(
e.getComponent(), e.getPoint(), zoomPanel);
// Resize panel
final Dimension currSize = zoomPanel.getSize();
zoomPanel.setPreferredSize(
new Dimension(
(int)(currSize.width * ZOOM_IN_FACTOR),
(int)(currSize.height * ZOOM_IN_FACTOR) ));
// Find out where our point on the zoom panel is now that we've resized it
final Point newViewPos = new Point();
newViewPos.x = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
newViewPos.y = (int)(ZOOM_IN_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
// Move the viewport to the new position to keep the area our mouse was in the same spot
getViewport().setViewPosition(newViewPos);
zoomPanel.revalidate();
}
public void zoomOut(final MouseWheelEvent e)
{
// Get the mouse position with respect to the zoomPanel
final Point pointOnZoomPanel = SwingUtilities.convertPoint(
e.getComponent(), e.getPoint(), zoomPanel);
// Resize panel
final Dimension currSize = zoomPanel.getSize();
zoomPanel.setPreferredSize(
new Dimension(
(int)(currSize.width * ZOOM_OUT_FACTOR),
(int)(currSize.height * ZOOM_OUT_FACTOR) ));
// Find out where our point on the zoom panel is now that we've resized it
final Point newViewPos = new Point();
newViewPos.x = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.x - e.getPoint().x);
newViewPos.y = (int)(ZOOM_OUT_FACTOR * pointOnZoomPanel.y - e.getPoint().y);
// Move the viewport to the new position to keep the area our mouse was in the same spot
getViewport().setViewPosition(newViewPos);
zoomPanel.revalidate();
}
}
Asked by: Darcy511 | Posted: 23-01-2022
Answer 1
Try instead finding the position of the mouse as a percentage of the current size, then applying that to the new size:
newViewPos.x = (int)((ZOOM_IN_FACTOR * currSize.width) * (e.getPoint().x/(double)currSize.width));
as an example. In this way, you are looking at the mouse position relative to the scroll pane, and preserving that relationship on the zoomPanel.
Answered by: Melissa597 | Posted: 24-02-2022Similar questions
java - JScrollPane - Zoom relative to mouse position
I need to calculate the new position of the viewport when zooming in to an image.
The UI is built up as follows:
ImagePanel draws the image
ImagePanelWrapper is a JPanel wrapping around the imagePanel
JScrollPane contains the ImagePanelWrapper
When zooming in or out, the ImagePanel's zoom factor is changed and the preferred size of the ImagePanel is being recalculated....
java - JScrollPane - Zoom relative to mouse position
I need to calculate the new position of the viewport when zooming in to an image.
The UI is built up as follows:
ImagePanel draws the image
ImagePanelWrapper is a JPanel wrapping around the imagePanel
JScrollPane contains the ImagePanelWrapper
When zooming in or out, the ImagePanel's zoom factor is changed and the preferred size of the ImagePanel is being recalculated....
java - JScrollPane now showing its viewport
I am making an application with Java Swing and i have a problem. I have made a Tabbed Panel, which need to hold a simple panel, and a scroll-panel. The simple panel is working fine but in my scroll-panel i can only see the scrollbars, but not the viewport, my code is as follows:
ContentPane
public class ContentPane extends JTabbedPane {
private InfoPanel ip;
ScrollPanel sp;
public InfoP...
Why does my jscrollpane result in odd paint calls in java swing?
I've got a routine that paints an insanely large graph inside a scroll pane. It's too big to paint before adding to the scrollpane - the menory requirements would be several gigs.
Because of the size of the graph I'm rendering the chart within the paint method of the scrollpane's child. Which works out well, however I'm noticing that every time a scrollbar is moved my paint routine is called twice - once with a cli...
java - Component in a JScrollPane stops receiving KeyEvents
I am putting a component ( derivative on JPanel ) inside a JScrollPane.
scrollPane = new JScrollPane(component);
since the component occasionally changes size, I have to occasionally do :
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
scrollPane.getViewport().setView(component);
component.repaint();
...
java - Make JScrollPane display scrollbars when JList inside is changed
I'm trying to change a JList inside a JScrollPane dynamically, using
myList.setListData(someArray);
After this I would expect the JScrollPane to show Scrollbars as needed, but this doesn't happen. Googling the issue was not very helpful. I tried various combinations of the following methods, with little success (basically poking through the api docs):
myScrollPane.setVertic...
java - Setting Scroll Bar on a JScrollPane
I have this JTextPane (wrapped in a JScrollPane) that is backed by a HTMLEditorKit. The contents of the JTextPane is simple HTML with some images (local files) embedded using img tags. The problem is that when you load the the JTextPane, it takes a split second to load and then it comes up with the scroll bar at the bottom of the page. If I do:
java - How do make an infinite jscrollpane?
I've implemented drag scroll before, but what's the best way to go about creating an infinite scroll pane? Of course there won't be any scrollbars and I will implement drag scroll.
What I am trying to do is implement dynamic loading on an infinite surface.
EDIT
Of course it wouldn't actually be infinite. I am asking how to fake it.
java - How to disable the default painting behaviour of wheel scroll event on JScrollPane
I recently purchased the book Filthy Rich Clients and i found it really useful and fun. Building on one example from the book i tried implementing a custom ScrollPane that displays a "shadow" on the bottom of its view over the component to be displayed. I ended up with the code below. It works but not perfectly. Specifically when i scroll the pane by dra...
java - How to prevent JScrollPane from scroll down on repaint?
I have got a JScrollPane with a diagram inside. The paintComponent Methode of the diagram is overridden. Now when the diagram paints itself, the scrollpane scrolls down to the buttom.
How do I prevent the scrolling?
I want the scrollpane / scrollbar to hold its position when painting.
Thanks in advance.
java - disable horizontal scroll in jscrollpane
I have a JScrollPane with FlowLayout that I want to have a fixed width. It should be scrolling vertically only, and the contents should be rearranged automatically when I resize the window. I think there should be a method like setEnableHorizontalScroll(false) but can't find it.
Is there any easy way to do this?
java - Remove Arrows from Swing Scrollbar in JScrollPane
I would like to remove the scrollbar arrow buttons from a scrollbar in a JScrollPane. How would I do this?
Still can't find your answer? Check out these amazing Java communities for help...
Java Reddit Community | Java Help Reddit Community | Dev.to Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)