Below is a bit of code that loads an image, and is supposed to allow the user to pan the image (which is in a JScrollPane) by clicking and dragging the mouse. It sort of works, but there are (at least) two problems. First, the image is jittery. It moves around, but it's jumpy. The cause of that problem is a total mystery to me. The second problem is that the distance moved by the mouse is not equal to the amount by which the image is moved. My guess is that the second problem is due to a mismatch between the logical coordinate system and the pixel coordinate system, but the two should be the same in this default case. I've been tinkering with this for a while and can't find any similar examples on the net. Any ideas?
-- You don't need an extended JPanel to just draw one image. Use a JLabel with the ImageIcon instead. Unless of course you are also adding components to the panel and have omitted that part for brevity.
-- If you do have a need for custom painting, it is pointless to construct an ImageIcon just to retrieve its Image. Read the Image by ImageIO instead. Unless you have to deal with an animated GIF, in which case you would use Toolkit and MediaTracker/ImageObserver.
-- Explicitly assigning null to fields is redundant. The default value is null for all reference types.
-- Why the empty statements in the empty methods? They just add clutter.
The solution I posted at JLabel pan image doesn't show any jitter. It's a SSCCE and loads an image available on the web, so you can run it without changes and see for yourself.
the distance moved by the mouse is not equal to the amount by which the image is moved. My guess is that the second problem is due to a mismatch between the logical coordinate system and the pixel coordinate system
There are no new questions, but there may be new answers.
Joined: Apr 18, 2011
I should have been more clear. I don't care about loading images; that was just something simple to exercise what I do care about: the way that scroll bars work and how they interact with the origin of the drawing. I should have said g.drawRect() for some arbitrary rectangle instead of messing with images. Let me play around with your suggestion and see if I can bring the intent over as a solution to my problem.
Joined: Apr 18, 2011
Darryl, I took your basic idea and reimplemented my original test class, without involving images at all. Instead, the program just draws a rectangle. I also got rid of the invokeLater() since I don't see why it's necessary here. Am I missing something?
Joined: Apr 18, 2011
I should have made it clear: the program that I just posted works perfectly, but I wonder why you bother with the invokeLater().
Randall Fairman wrote:I also got rid of the invokeLater() since I don't see why it's necessary here. Am I missing something?
All user interface interaction, including the creation, should be done on the Event Dispatcher Thread (EDT). EventQueue.invokeLater / SwingUtilities.invokeLater (they do the same) will take the Runnable and execute its run() method on this EDT.
Yes, I understand that about invokeLater(). Below is the mouseDragged() from your original example. The code that's inside invokeLater() doesn't do anything to the UI. Indeed, it doesn't seem to do anything at all. Your original program runs just fine if you remove the entire invokeLater() block. The values of pressed and visiRect, which are the only two things that are modified are the same before and after that code is executed. You must have had some reason to put it there?
You're correct. That code was left over from a more advanced DragScrollHandler that included a Timer to create "inertia" of scrolling after the mouse button was released. I've made corrections n the thread linked.
@Rob: The code is already on the EDT, being in an event listener method.
edit Scratch that first. Try continuing to drag when the scrolled component has already reached its limit, then without releasing the mouse button drag back slowly. Try it with and without the code in the invokeLater.
Calling scrollRectToVisible doesn't always change the visibleRect.
You're right. Using invokeLater() is one way to fix the problem, or my version of mouseDragged(), in DrawPanel3, could be modified slightly to read.
This does act slightly differently than your version since the point of the original mouse click remains the "reference point" for the pan, even after you attempt to pan beyond the edge of the image. If that behavior is undesired, then the value of pressed could be modified too when visiRect goes beyond it's natural bounds.
Randall Fairman wrote:The code that's inside invokeLater() doesn't do anything to the UI.
It does interact with the UI - it queries the component. But since the invokeLater is called from the EDT the only reason to do this is to run this code later. Sometimes it's required, for instance when calling requestFocus on a component.