Skip to main content

ScrollPane utility

39 replies [Last post]
weebib
Offline
Joined: 2004-08-20

Hello,

I had an idea the other day about something that might come in handy when dealing with big components in scrollPanes. I would imagine this has already been done somewhere so credit given to whomever got the idea first.

import javax.swing.*;<br />
import javax.swing.event.MouseInputAdapter;<br />
import javax.swing.event.MouseInputListener;<br />
import javax.imageio.ImageIO;<br />
import java.awt.*;<br />
import java.awt.geom.Area;<br />
import java.awt.image.BufferedImage;<br />
import java.awt.event.ActionEvent;<br />
import java.awt.event.MouseEvent;<br />
import java.io.IOException;<br />
import java.net.URL;</p>
<p>public class ScrollPaneBidule extends JComponent {<br />
	private static final double MAX_SIZE = 200;<br />
	private JScrollPane theScrollPane;<br />
	private JComponent theComponent;<br />
	private JPopupMenu thePopupMenu;<br />
	private JButton theButton;<br />
	private BufferedImage theImage;<br />
	private Rectangle theStartRectangle;<br />
	private Rectangle theRectangle;<br />
	private Point theStartPoint;<br />
	private double theScale;</p>
<p>	public ScrollPaneBidule(JScrollPane aScrollPane) {<br />
		setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));<br />
		theScrollPane = aScrollPane;<br />
		theComponent = (JComponent)theScrollPane.getViewport().getView();<br />
		theImage = null;<br />
		theStartRectangle = null;<br />
		theRectangle = null;<br />
		theStartPoint = null;<br />
		theScale = 0.0;<br />
		theButton = new JButton(new AbstractAction("...") {<br />
			public void actionPerformed(ActionEvent e) {<br />
				display();<br />
			}<br />
		});<br />
		theScrollPane.setCorner(JScrollPane.LOWER_RIGHT_CORNER, theButton);<br />
		setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));<br />
		MouseInputListener mil = new MouseInputAdapter() {<br />
			public void mousePressed(MouseEvent e) {<br />
				theStartPoint = e.getPoint();<br />
			}</p>
<p>			public void mouseReleased(MouseEvent e) {<br />
				if (theStartPoint != null) {<br />
					Point newPoint = e.getPoint();<br />
					int deltaX = (int)((newPoint.x - theStartPoint.x) / theScale);<br />
					int deltaY = (int)((newPoint.y - theStartPoint.y) / theScale);<br />
					scroll(deltaX, deltaY);<br />
				}<br />
				theStartPoint = null;<br />
				theStartRectangle = theRectangle;<br />
			}</p>
<p>			public void mouseDragged(MouseEvent e) {<br />
				if (theStartPoint == null) return;<br />
				Point newPoint = e.getPoint();<br />
				moveRectangle(newPoint.x - theStartPoint.x, newPoint.y - theStartPoint.y);<br />
			}<br />
		};<br />
		addMouseListener(mil);<br />
		addMouseMotionListener(mil);<br />
		thePopupMenu = new JPopupMenu();<br />
		thePopupMenu.setLayout(new BorderLayout());<br />
		thePopupMenu.add(this, BorderLayout.CENTER);<br />
		thePopupMenu.setBorder(BorderFactory.createLineBorder(Color.BLACK));<br />
	}</p>
<p>	protected void paintComponent(Graphics g1D) {<br />
		if (theImage == null || theRectangle == null) return;<br />
		Graphics2D g = (Graphics2D)g1D;<br />
		Insets insets = getInsets();<br />
		int xOffset = insets.left;<br />
		int yOffset = insets.top;<br />
		int availableWidth = getWidth() - insets.left - insets.right;<br />
		int availableHeight = getHeight() - insets.top - insets.bottom;<br />
		g.drawImage(theImage, xOffset, yOffset, null);<br />
		Color tmpColor = g.getColor();<br />
		Area area = new Area(new Rectangle(xOffset, yOffset, availableWidth, availableHeight));<br />
		area.subtract(new Area(theRectangle));<br />
		g.setColor(new Color(255, 255, 255, 128));<br />
		g.fill(area);<br />
		g.setColor(Color.BLACK);<br />
		g.draw(theRectangle);<br />
		g.setColor(tmpColor);<br />
	}</p>
<p>	public Dimension getPreferredSize() {<br />
		if (theImage == null || theRectangle == null) return new Dimension();<br />
		Insets insets = getInsets();<br />
		return new Dimension(theImage.getWidth(null) + insets.left + insets.right,<br />
							 theImage.getHeight(null) + insets.top + insets.bottom);<br />
	}</p>
<p>	private void display() {<br />
		double compWidth = theComponent.getWidth();<br />
		double compHeight = theComponent.getHeight();<br />
		double scaleX = MAX_SIZE / compWidth;<br />
		double scaleY = MAX_SIZE / compHeight;<br />
		theScale = Math.min(scaleX, scaleY);</p>
<p>		theImage = new BufferedImage((int)(theComponent.getWidth() * theScale),<br />
									 (int)(theComponent.getHeight() * theScale),<br />
									 BufferedImage.TYPE_INT_RGB);</p>
<p>		Graphics2D g = theImage.createGraphics();<br />
		g.scale(theScale, theScale);<br />
		theComponent.paint(g);</p>
<p>		theStartRectangle = theComponent.getVisibleRect();<br />
		Insets insets = getInsets();<br />
		theStartRectangle.x = (int)(theScale * theStartRectangle.x + insets.left);<br />
		theStartRectangle.y = (int)(theScale * theStartRectangle.y + insets.right);<br />
		theStartRectangle.width *= theScale;<br />
		theStartRectangle.height *= theScale;<br />
		theRectangle = theStartRectangle;</p>
<p>		Dimension pref = thePopupMenu.getPreferredSize();</p>
<p>		thePopupMenu.show(theButton,<br />
						  (theButton.getWidth() - pref.width) / 2,<br />
						  (theButton.getHeight() - pref.height) / 2);</p>
<p>		try {<br />
			Robot robot = new Robot();<br />
			Point centerPoint = new Point(theRectangle.x + theRectangle.width / 2,<br />
										  theRectangle.y + theRectangle.height / 2);<br />
			SwingUtilities.convertPointToScreen(centerPoint, this);<br />
			robot.mouseMove(centerPoint.x, centerPoint.y);<br />
		} catch (AWTException e) {<br />
			e.printStackTrace();<br />
		}<br />
	}</p>
<p>	private void moveRectangle(int aDeltaX, int aDeltaY) {<br />
		if (theStartRectangle == null) return;<br />
		Insets insets = getInsets();<br />
		Rectangle newRect = new Rectangle(theStartRectangle);<br />
		newRect.x += aDeltaX;<br />
		newRect.y += aDeltaY;<br />
		newRect.x = Math.min(Math.max(newRect.x, insets.left), getWidth() - insets.right - newRect.width);<br />
		newRect.y = Math.min(Math.max(newRect.y, insets.right), getHeight() - insets.bottom - newRect.height);<br />
		Rectangle clip = new Rectangle();<br />
		Rectangle.union(theRectangle, newRect, clip);<br />
		clip.grow(2, 2);<br />
		theRectangle = newRect;<br />
		paintImmediately(clip);<br />
	}</p>
<p>	private void scroll(int aDeltaX, int aDeltaY) {<br />
		JComponent component = (JComponent)theScrollPane.getViewport().getView();<br />
		Rectangle rect = component.getVisibleRect();<br />
		rect.x += aDeltaX;<br />
		rect.y += aDeltaY;<br />
		component.scrollRectToVisible(rect);<br />
		thePopupMenu.setVisible(false);<br />
	}</p>
<p>	public static void main(String[] args) {<br />
		EventQueue.invokeLater(new Runnable() {<br />
			public void run() {<br />
				try {<br />
					JFrame frame = new JFrame(ScrollPaneBidule.class.getName());<br />
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />
					URL imageURL = new URL("http://www.aboutstonehenge.info/images/education/stonehenge-wallpaper-1.jpg");<br />
					JLabel label = new JLabel(new ImageIcon(ImageIO.read(imageURL)));<br />
					JScrollPane scrollPane = new JScrollPane(label);<br />
					new ScrollPaneBidule(scrollPane);<br />
					frame.setContentPane(scrollPane);<br />
					frame.pack();<br />
					frame.setVisible(true);<br />
				} catch (IOException e) {<br />
					e.printStackTrace();<br />
				}<br />
			}<br />
		});<br />
	}<br />
}
Needless to say that this is more a "proof of concept" than a real implementation. I pretty much removed all of the error handling code to make it shorter.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
antk
Offline
Joined: 2006-04-13

> Hi antk,
>
> Nice idea indeed. This could actually become a user
> defined option, a bit like that of the JSplitPane
> which determines whether components should layout
> continously.
>
> Pierre.

Thats exactly the idea. But be warned !!!. That was a really quick hack.

Now on to another (slightly more technical) request if I may.
During my custom component crafting days I have occasionally created components that adjust their painting depending on whether their immediate ancestor is a JViewport instance. For a quick example imagine a component that displays a large image and superimposes a label on the upper-left corner of the viewport when the component is within a JViewport so that the label is always visible. As another example consider a component designed to display a time range (say a week). The user can drag and change the scale so that he can get visible ticks every 2-hours, hour, 15-minutes or even down to minutes. The component is designed to be used within JViewports (actually in a JViewport acting as a ScrollPane column header). When the scale is detailed enough the component displays the hour whose portion is visible on the left side of the viewport view on the viewport. I guess you'll probably need a screenshot to understand the later example and I could provide one (or even a demo) if requested.
Anyway, there is ocassionally a need to create components that vary their painting depending on their parent being a JViewport instance. These components are usually designed and intended to be used within JViewports. Now when the ScrollPaneSelector calls paintImmediately() on these components to get the thumbnail image the resulting image will not be applicable for the thumbnail (the image component I mentioned above will draw the image and then paint the image label to wherever the JViewport position happens to be).
I suggest declaring an interface (say ThumbnailProvider) declared as:
[code]
interface ThumbnailProvider {

public void paintThumbnail( Graphics g);

}
[/code]

The ScrollPaneSelector then could be modified to check if the component in the viewport implements this interface and then call paintThumbnail() instead of paint() in order to get the thumbnail picture. This way the component can arrange so that whatever annotations are painted (because of the JViewport parent) will not be painted. If the interface is not implemented ScrollPaneSelector cann fall-back to it's default stratefy and get the thumbnail through paint().

Please, do excuse my verbosity. I am just trying to get the idea across...

Looking forward to your comments,
Antonis

antk
Offline
Joined: 2006-04-13

Hi Pierre,
to fully understand what I meant in my previous post, try puting the following custom JLabel (configured with a large image) in a scroll- pane where a ScrollPaneSelector is installed.
[code]
package test;

import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;

import javax.swing.*;

/**
*
* Created on Sep 12, 2006
*
* @author antk
*
*/
public class LabeledLargeImage
extends
JLabel
{

private String m_label = "This is a sample label";

/**
* @param image
*/
public LabeledLargeImage( Icon image)
{
super( image);
}

/* (non-Javadoc)
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
*/
protected void paintComponent( Graphics g)
{
super.paintComponent( g);
int currentPosition;

if ( getParent() instanceof JViewport)
{
JViewport vp = (JViewport) getParent();
currentPosition = vp.getViewPosition().x;
}
else
currentPosition = 0;

Graphics2D g2 = (Graphics2D)g;
g2.setColor( Color.WHITE);
GlyphVector vector = font.createGlyphVector( new FontRenderContext( null, true, true), m_label);

FontMetrics indicatorFM = g2.getFontMetrics( font);
g2.drawGlyphVector( vector, currentPosition + 8 , indicatorFM.getMaxAscent());
g2.setColor( Color.BLACK);
g2.draw( vector.getOutline( currentPosition + 8, indicatorFM.getMaxAscent()));

}

private static final Font font = new Font( "Dialog", Font.BOLD, 30 );
/* (non-Javadoc)
* @see javax.swing.JLabel#setText(java.lang.String)
*/
public void setText( String text)
{
m_label = text;
repaint();
}

/* (non-Javadoc)
* @see javax.swing.JLabel#getText()
*/
public String getText()
{
return null;
}

}

[/code]

Best Regards,
Antonis

antk
Offline
Joined: 2006-04-13

I am sorry !!!

paintComponent() should really be:

[code]
protected void paintComponent( Graphics g)
{
super.paintComponent( g);
int currentPosition;
int currentYPosition;

if ( getParent() instanceof JViewport)
{
JViewport vp = (JViewport) getParent();
currentPosition = vp.getViewPosition().x;
currentYPosition = vp.getViewPosition().y;
}
else
{
currentPosition = 0;
currentYPosition = 0;

}

Graphics2D g2 = (Graphics2D)g;
g2.setColor( Color.WHITE);
GlyphVector vector = font.createGlyphVector( new FontRenderContext( null, true, true), m_label);

FontMetrics indicatorFM = g2.getFontMetrics( font);
g2.drawGlyphVector( vector, currentPosition + 8 , currentYPosition + indicatorFM.getMaxAscent());
g2.setColor( Color.BLACK);
g2.draw( vector.getOutline( currentPosition + 8, currentYPosition+ indicatorFM.getMaxAscent()));

}
[/code]

antk
Offline
Joined: 2006-04-13

Hi Pierre,

Your scroll pane 'thingy' is, simply put, a splendid idea beautifully executed !!!

To add my two cents to an already excellent work I would suggest (if I may) the possibility to have the scroll pane adjusted dynamically when the thumbnail is dragged. After almost six minutes of playing with the code I was able to achieve this by :

- changing the [b]ScrollPaneSelector.scroll()[/b] method to the following:
[code]
private void scroll(int aDeltaX, int aDeltaY, boolean hide) {
if (theComponent == null) return;
Rectangle rect = theComponent.getVisibleRect();
rect.x += aDeltaX;
rect.y += aDeltaY;
theComponent.scrollRectToVisible(rect);
if (hide )
thePopupMenu.setVisible(false);
}
[/code]

- and changing the [b]MouseInputAdapter[/b] installed in the selector's constructor to the following:
[code]
MouseInputListener mil = new MouseInputAdapter() {
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
SwingUtilities.convertPointToScreen(p, theButton);
display(p);
}

public void mouseReleased(MouseEvent e) {
if (theStartPoint != null) {
Point newPoint = e.getPoint();
SwingUtilities.convertPointToScreen(newPoint, (Component)e.getSource());
int deltaX = (int)((newPoint.x - theStartPoint.x) / theScale);
int deltaY = (int)((newPoint.y - theStartPoint.y) / theScale);
scroll(deltaX, deltaY, true);
}
theStartPoint = null;
theStartRectangle = theRectangle;
}

public void mouseDragged(MouseEvent e) {
if (theStartPoint == null) return;
Point newPoint = e.getPoint();
SwingUtilities.convertPointToScreen(newPoint, (Component)e.getSource());
moveRectangle(newPoint.x - theStartPoint.x, newPoint.y - theStartPoint.y);
int deltaX = (int)((newPoint.x - theStartPoint.x) / theScale);
int deltaY = (int)((newPoint.y - theStartPoint.y) / theScale);
scroll(deltaX, deltaY, false);
theStartPoint = newPoint;
theStartRectangle = theRectangle;
}
};
[/code]

As I noted earlier (and cannot overemphasize enough) this is a very quick hack and I wouldn't be surprised if I have missed something (so please review). Of course, this could be made into an option by having a boolean property control this behaviour.

Thanks a lot for such an excellent contribution !!!

Best Regards,
Antonis

weebib
Offline
Joined: 2004-08-20

Hi antk,

Nice idea indeed. This could actually become a user defined option, a bit like that of the JSplitPane which determines whether components should layout continously.

Pierre.

pdoubleya
Offline
Joined: 2004-02-09

Pierre

Could you check your ScrollPaneSelectorDemo class into the incubator so I can try this suggested change out?

Thanks
patrick

weebib
Offline
Joined: 2004-08-20

Hey Patrick,

It's already there, actually :
https://jdnc-incubator.dev.java.net/source/browse/jdnc-incubator/src/wee...

Pierre.

Patrick Wright

Ah, I was looking uder weebib/java, thanks.

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

> Pierre
>
> This is FANTASTIC! Totally the reason why SwingLabs
> is such a good
> idea. I'm glad I built your test and tried it out,
> this really rocks.

Well, thank you very much for the feedback.

> I hope it's OK--I uploaded this with a WebStart file
> to my server,
> http://www.pdoubleya.com/projects/swinglabs/swingx/dem
> os/scrollpanebidule/ScrollPaneBidule.jnlp
>
> or, make it tiny
> http://tinyurl.com/zptc8

No problem at all. That will indeed make it easier to test.

> Check it out, people! Just resize the window
> (smaller) and click on
> the control at the bottom right corner of the window.
> You can move the
> scroll selector around with the mouse to control
> which part of the
> image you are viewing.

"Scroll Selector" : that's how it should be called (I was struggling to come up with a right name). Thanks ;)

> Would you like to sign the JCA and contribute this to
> the incubator?
> http://wiki.java.net/bin/view/Javadesktop/SwingLabsHow
> ToHelp

I will. I'm just busy right now since I'm changing job and moving from Nantes to Paris.

> I have not checked it in to SwingLabs.

Feel free to do so. It's posted under the "Do whatever you want with this code" license :)

> I think there are all sorts of cool ideas this could
> lead to--just
> having that popup image to control the placement of
> the scroll leads
> to interesting possibilities...

I'd be interested in hearing about possible extensions, ameliorations...

As I just said in my previous post, there should be a means to make the button appear even when only one of the scroll bars is visible. I hope (haven't even started to work on it) this is possible by just subclassing ScrollPaneLayout because I wish this could remain "lightweight" in that it should just be an add-on to existing JScrollPanes.

> Thanks a lot for sending this out!
> Patrick
You're very welcome

Patrick Wright

Pierre
> > Would you like to sign the JCA and contribute this to
> > the incubator?
> > http://wiki.java.net/bin/view/Javadesktop/SwingLabsHow
> > ToHelp
>
> I will. I'm just busy right now since I'm changing job and moving from Nantes to Paris.
>
> > I have not checked it in to SwingLabs.
>
> Feel free to do so. It's posted under the "Do whatever you want with this code" license :)

I don't believe we can do that unless you have signed the JCA and then
contributed it; otherwise, I think we can only use very very small
amounts of code. If you're planning to sign the JCA sometime soon, we
can wait till then; people can still run locally to check it out.
Richard, if you see anyway around that limitation, I can check the
demo into the incubator as is.

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

Patrick,

I understand. I will sign the JCA anytime soon (during the week, probably).

Pierre

Patrick Wright

> I understand. I will sign the JCA anytime soon (during the week, probably).

Great! It will be good to have you on board. The legal stuff is
sometimes annoying when good ideas come through the Net, but there you
have it.

Regards
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

Hey Patrick,

I did sign the JCA but I don't know if I'm supposed to receive some kind of feedback before I have commit access to the incubator.

In the meantime, I've worked on improving ScrollPaneSelector. I guess it's ready for commit.

While I was browsing through my personal little projects (I have loads of them), I re-discovered a class that I had coded a while ago, back at the time when I often would try to imitate cool features I found in IntelliJ IDEA.

It's basically a "HoverManager" that detects when a cell from a JList, JTree or JTable is hovered upon and then paints it to its preferredSize, no matter what the available space is. Should I post it on this forum first or commit it in the incubator?

Patrick Wright

Hi Pierre

On 4/26/06, jdnc-interest@javadesktop.org wrote:
> Hey Patrick,
>
> I did sign the JCA but I don't know if I'm supposed to receive some kind of feedback before I have commit access to the incubator.

To make sure your request didn't get lost, I just pinged Richard about
the JCA. He'll confirm when he's received it, and you'll be granted
incubator access. The JCA processing process is a little byzantine
because it has to be picked up by someone who's looking for the
things.

>
> In the meantime, I've worked on improving ScrollPaneSelector. I guess it's ready for commit.

Great!

>
> While I was browsing through my personal little projects (I have loads of them), I re-discovered a class that I had coded a while ago, back at the time when I often would try to imitate cool features I found in IntelliJ IDEA.
>
> It's basically a "HoverManager" that detects when a cell from a JList, JTree or JTable is hovered upon and then paints it to its preferredSize, no matter what the available space is. Should I post it on this forum first or commit it in the incubator?

I recommend that you commit to the incubator and mail a link to a
demo, better if it's a JNLP. If you post the code here, people have to
cut and paste it into a file with the SwingX stuff ready and then run
it, which not everyone can do, and then it can get lost in the
shuffle. If you don't have a JNLP ready, commit to the incubator and
let people know it's there.

It seems to help when you write up exactly what it does and how it can help.

Cheers!
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

Hi again.

Hmmm. I checked out the incubator project and wasn't allowed to add my "weebib" package within the incubator's package so it seems that I don't have a commit access yet.

If that helps, I sent my JCA by e-mail a week ago.

Pierre.

Patrick Wright

On 4/26/06, jdnc-interest@javadesktop.org wrote:
> Hi again.
>
> Hmmm. I checked out the incubator project and wasn't allowed to add my "weebib" package within the incubator's package so it seems that I don't have a commit access yet.
>
> If that helps, I sent my JCA by e-mail a week ago.

Look like you are not on the members list yet
https://jdnc-incubator.dev.java.net/servlets/ProjectMemberList

Let's see what Richard says when he gets my email.

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

Hello,

I still haven't received any feedback on the subject :|
What should I do?

Pierre.

Patrick Wright

Richard

Can you check if Pierre's JCA was received? He sent it right before
JavaOne, so nobody followed up then.

Thanks
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

I haven't seen it come in. Is there any way you can email it to me directly, Pierre?

Richard

rbair
Offline
Joined: 2003-07-08

Got it! You now have commit access to the incubator. Enjoy.

Richard

weebib
Offline
Joined: 2004-08-20

> Got it! You now have commit access to the incubator.
> Enjoy.
Thanks, I will.
Pierre

pandaman
Offline
Joined: 2009-09-18

Hello

This excellent work seems abandoned. I've been checking it sometimes since last 3 years. Last post points a little problem, with a solution.

Why not propose a jar with all the improvements discussed here?

Pierre, une super contribution française qui mérite plus de visibilité.

gorgodon
Offline
Joined: 2005-12-30

Hi,

I really like this piece of work but detected a little problem. If the button which is opening the popup with the preview-image is on the lower right corner of the monitor the mouse-cursor is not adjusted correctly (Tested with Windows XP, java 1.6.0-b105). This will lead to the problem that the viewport can not be moved to the lower right corner of the scrollpane because mouse-movement will stop at screen-border.

To reproduce start the Webstart-Demo (https://jdnc-incubator.dev.java.net/demos/weebib/scrollpaneselector/scro...) and place the opened application to the lower right corner (icon should be exactly in the corner of your monitor). The Popup will not open on the defined location (which would cause the popup to move half out of the screen) but in a manner that the Popup is completely visible.

Because the real position is not the defined the centerPoint to which the mouse is moved is not correct.

I have the following solution to fix this problem:
- Detect the position of the opened popup
- Check against the expected position
- If not the expected Position move the cursor

Why this solution?
- It's not completeley predictable where the popup will open, so use it's real position to fix a possible displacement.

Here my proposed code patching display:
[code]
private void display(Point aPointOnScreen) {
if (theComponent == null) return;
double compWidth = theComponent.getWidth();
double compHeight = theComponent.getHeight();
double scaleX = MAX_SIZE / compWidth;
double scaleY = MAX_SIZE / compHeight;
theScale = Math.min(scaleX, scaleY);
int scaledWidth = (int) (theComponent.getWidth() * theScale);
int scaledHeight = (int) (theComponent.getHeight() * theScale);
theImage = new BufferedImage(scaledWidth,
scaledHeight,
BufferedImage.TYPE_INT_ARGB);

Graphics2D g = theImage.createGraphics();
g.scale(theScale, theScale);
theComponent.paint(g);
theStartRectangle = theComponent.getVisibleRect();
Insets insets = getInsets();
theStartRectangle.x = (int)(theScale * theStartRectangle.x + insets.left);
theStartRectangle.y = (int)(theScale * theStartRectangle.y + insets.right);
theStartRectangle.width *= theScale;
theStartRectangle.height *= theScale;
theRectangle = theStartRectangle;

Dimension pref = thePopupMenu.getPreferredSize();
Point buttonLocation = theButton.getLocationOnScreen();
Point popupLocation = new Point((theButton.getWidth() - pref.width) / 2,
(theButton.getHeight() - pref.height) / 2);
Point centerPoint = new Point(buttonLocation.x + popupLocation.x + theRectangle.x + theRectangle.width / 2,
buttonLocation.y + popupLocation.y + theRectangle.y + theRectangle.height / 2);
boolean movedByRobot = false;
try {
// Attempt to move the mouse pointer to the center of the selector's rectangle.
new Robot().mouseMove(centerPoint.x, centerPoint.y);
movedByRobot = true;
theStartPoint = centerPoint;
} catch (Exception e) {
// Since we cannot move the cursor, we'll move the popup instead.
theStartPoint = aPointOnScreen;
e.printStackTrace();
popupLocation.x += theStartPoint.x - centerPoint.x;
popupLocation.y += theStartPoint.y - centerPoint.y;
}
thePopupMenu.show(theButton, popupLocation.x, popupLocation.y);
if (movedByRobot) {
Point newPopupLocationOnScreen = thePopupMenu.getLocationOnScreen();
Point expectedPopupLocationOnScreen = new Point(buttonLocation);
expectedPopupLocationOnScreen.translate(popupLocation.x, popupLocation.y);
if (!newPopupLocationOnScreen.equals(expectedPopupLocationOnScreen)) {
// popup not at expected place, have to move mouseCursors
Point newCenterPoint = new Point(centerPoint.x + (newPopupLocationOnScreen.x - expectedPopupLocationOnScreen.x ), centerPoint.y + (newPopupLocationOnScreen.y - expectedPopupLocationOnScreen.y));
try {
new Robot().mouseMove(newCenterPoint.x, newCenterPoint.y);
movedByRobot = true;
theStartPoint = newCenterPoint;
} catch (AWTException e) {
// we can not do anything anymore, position of cursor is now wrong
}
}
}
}
[/code]

Or does anybody have a better solution for this problem? Suggestions or comments are wellcome!

Greetings

Gerhard

reden
Offline
Joined: 2004-01-02

That is very nice, Pierre. Nice work!

nomike
Offline
Joined: 2006-05-30

How about this:

I click the left MouseButton on the Button and hold it.
The preview is displayed and I could move the Mouse to the Area I need. As I release the MouseButton the ScrollPane scrolls to the location I specified. I remember this behavior in some Corel PhotoPaint or Adobe Photoshop Application.

Maybe it would be good to paramterize this...

nomike aka Michael Postmann

PS: ...this is just AMAZING!

weebib
Offline
Joined: 2004-08-20

> How about this:
>
> I click the left MouseButton on the Button and hold
> it.
> The preview is displayed and I could move the Mouse
> to the Area I need. As I release the MouseButton the
> ScrollPane scrolls to the location I specified. I
> remember this behavior in some Corel PhotoPaint or
> Adobe Photoshop Application.

Interestingly enough, this is exactly the behavior I implemented in my next version.

This will be available as soon as I succeed in committing my project on cvs. For some obscure reasons, I wasn't able (allowed ?) to do a simple check out of the jdnc package. I'll look further into it this week-end.

gfx
Offline
Joined: 2003-06-14

J'adore ton composant Pierre. Merci !

weebib
Offline
Joined: 2004-08-20

@reden : thanks
@gfx : Merci à toi.

So I finally created my project. I have no idea though how to make it available as a java web start, as I don't have a web site of my own.

Also, am I supposed to send a e-mail to the incubator's mailing list?

Patrick Wright

> So I finally created my project. I have no idea though how to make it available as a java web start, as I don't have a web site of my own.

You can post the JNLP and related files to the incubator, and then
publish the URL here. Put them in the incubator under www/{some
subdirectory} and they will have the main project (the incubator's)
URL, like
https://jdnc-incubator.dev.java.net/pierres_sample_1

If you look at the home page for the incubator (www/index.html) you'll
see two (old) links to JNLP files that show how this is done.

>
> Also, am I supposed to send a e-mail to the incubator's mailing list?

No, for historical reasons the JDNC mailing list is used for all this stuff.

Regards
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20
Patrick Wright

Hey Pierre

Nice job, thanks for posting the JNLP.

Some quick suggestions, basically to make it easier for users to
figure out what is going on.

1) would it be possible to size the frame down to start with, so that
the scrollbars and the selector show up automatically?

2) might be nice to have a one-liner of text at the top or bottom to
explain what is going on.

Also, would you like to edit the index.html for the incubator and add
the JNLP link to the small table of samples we have?

Nice work! I really like this component.

Regards
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

weebib
Offline
Joined: 2004-08-20

Hey Patrick,

Thanks for those suggestions. It's all done.

Pierre

David Bolsover

Excellent piece of work!

David

-----Original Message-----
From: jdnc-interest@javadesktop.org [mailto:jdnc-interest@javadesktop.org]
Sent: 17 June 2006 23:04
To: jdnc@jdnc.dev.java.net
Subject: Re: ScrollPane utility

Hey Patrick,

Thanks for those suggestions. It's all done.

Pierre
[Message sent by forum member 'weebib' (weebib)]

http://forums.java.net/jive/thread.jspa?messageID=124275

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

--
No virus found in this incoming message.
Checked by AVG Anti-Virus.
Version: 7.1.394 / Virus Database: 268.9.0/368 - Release Date: 16/06/2006

--
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.1.394 / Virus Database: 268.9.0/368 - Release Date: 16/06/2006

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rbair
Offline
Joined: 2003-07-08

Hi,

What does the name ScrollPaneBidule mean?

I'll try to run it again by making the window smaller -- I never did get the little button to appear last time :)

Richard

weebib
Offline
Joined: 2004-08-20

> Hi,
Hello,

>
> What does the name ScrollPaneBidule mean?
>

"Bidule" is the french for thingy. I just couldn't find a more appropriate term.

> I'll try to run it again by making the window smaller
> -- I never did get the little button to appear last
> time :)

It's just that I use one of the JScrollPane's corners to place the button. I should subclass ScrollPaneLayout to ensure that this button appears when at least one of the scrollBars is visible.

Pierre

> Richard

Patrick Wright

Pierre

This is FANTASTIC! Totally the reason why SwingLabs is such a good
idea. I'm glad I built your test and tried it out, this really rocks.

I hope it's OK--I uploaded this with a WebStart file to my server,
http://www.pdoubleya.com/projects/swinglabs/swingx/demos/scrollpanebidul...

or, make it tiny
http://tinyurl.com/zptc8

Check it out, people! Just resize the window (smaller) and click on
the control at the bottom right corner of the window. You can move the
scroll selector around with the mouse to control which part of the
image you are viewing.

Would you like to sign the JCA and contribute this to the incubator?
http://wiki.java.net/bin/view/Javadesktop/SwingLabsHowToHelp

I have not checked it in to SwingLabs.

I think there are all sorts of cool ideas this could lead to--just
having that popup image to control the placement of the scroll leads
to interesting possibilities...

Thanks a lot for sending this out!
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

evickroy
Offline
Joined: 2004-07-23

Very Cool! One thing though.... On Mac OS X, the window resize gripper is in the lower-right corner, so it is very difficult to get to your button.

Erik

weebib
Offline
Joined: 2004-08-20

> Very Cool! One thing though.... On Mac OS X, the
> window resize gripper is in the lower-right corner,
> so it is very difficult to get to your button.
>
> Erik

How embarrassing... I'm a Mac user too, at home. I didn't even take time to test it at home. As far as I can remember, the Mac OS' HIG suggests to put an EmptyBorder on the JFrame's contentPane or to add some kind of a status bar.

weebib
Offline
Joined: 2004-08-20

I forgot to add that you need to reduce the frame's size enough to make both scroll bars visible and to make the little button appear at the bottom right corner.