3

I have a JScrollPane whose viewport is a subclass of JPanel. This panel is laid out with a BoxLayout and upon user interaction the horizontal width of the components can change. When there are sufficient components such that the scroll bars are needed, changing the horizontal size of the component and then calling revalidate() on the JPanel subclass (the viewport view) will always cause the scroll pane to reset to (0,0).

I would like to keep the current view, so I've set up a component listener and on componentMoved() I store the value at getLocation() (this is all in the JPanel subclass or the viewport view). Immediately after calling revalidate() I call setLocation() with the stored location (on the event dispatch thread). However, that causes jumpiness where the view position is set to (0,0) then jumps immediately to the stored location. Is there a way to stop the JScrollPane from going back to (0,0)? Is there a better way to tell it that the size of it's viewport view has changed?

I've tried to figure out where the (0,0) is coming from by subclassing the JScrollBar and overriding setValue() and putting a breakpoint, but it's not being hit there (but is when I move the scroll wheel) so I assume it's being set internally. Does anyone know what might be happening?

mKorbel
  • 108,320
  • 17
  • 126
  • 296
user450775
  • 437
  • 1
  • 5
  • 13
  • 2
    For better help sooner, post your code as an [SSCCE](http://www.sscce.org) that demonstrates your problem. This allows users to copy/paste and reproduce your issue. – Duncan Jones Aug 09 '13 at 09:18
  • I would have, but the SSCCE I had developed for this question wasn't showing the issue. It would seem that because it was so small, the "race condition" didn't happen (I could never visibly see the jump). The project I have is so large I couldn't just post it so I was hoping that my description was good enough :( – user450775 Aug 09 '13 at 17:59

1 Answers1

3

Try another way to call the code after revalidate() buf before repaint().

scrollPane.getViewport().setViewPosition(new Point(x,y));

Alternatively you can try to call panel.scrollRectToVisible(Rectangle)

mKorbel
  • 108,320
  • 17
  • 126
  • 296
StanislavL
  • 55,186
  • 9
  • 58
  • 88
  • Thanks, I will give that a shot. When you say "before repaint()" do you mean before I directly invoke repaint()? Doesn't revalidate() call repaint() eventually after it's re-laid out its components? I'm not actually calling repaint() myself after revalidate(), maybe I need to (I wasn't because I could see the screen update so I figured it was being called somewhere within repaint()). – user450775 Aug 09 '13 at 18:02
  • Ok, I tried what you said and it didn't work. But it got me thinking. After trying a whole bunch of other things (removing some calls, changing some around, etc..) I went back to do exactly what you said. I went with "revalidate();repaint();" and it worked! The only thing different is that I am not calling setSize() on it. I thought I needed to since the size of the component changed, but just having getPreferredSize() return the proper size made everything work. TL;DR: made sure the only calls I had were to revalidate(); and repaint(); didn't event need to remember the position and set it – user450775 Aug 10 '13 at 05:17