2

I've got a JPanel inside a JScrollPane. I draw things in the JPanel, and at some point I might draw past the width of the JScrollPane. In this case, I'd like the horizontal scroll bar to appear, and I'd like to be able to scroll around to view different parts of the JPanel. However, I end up clearing the JScrollPane.

frame = new JFrame();
frame.setBounds(100, 100, 1000, 800);
localScrollPane = new JScrollPane();
localScrollPane.setBounds(768, 6, 226, 350);
frame.getContentPane().add(localScrollPane);        
localView = new JPanel();
localScrollPane.setViewportView(localView);

drawSomeThings(localView.getGraphics());
// wait for user input
int newWidth = drawThingsPastTheWidth(localView.getGraphics());

// these next two lines clear it
localView.setPreferredSize(new Dimension(newWidth, localView.getHeight()));
localView.revalidate();

What am I doing wrong? Thanks!

Vinay
  • 61
  • 7
  • don't use getGraphics - afaik, that will just produce a snapshot which most probably will be over-painted (with the comp's background) next time paintComponent is called internally. Instead, keep the state that produces the drawing and redraw from that state in paintComponent. If that's too slow, draw into a bufferedImage and draw the image if nothing else has changed – kleopatra Nov 09 '11 at 15:16

4 Answers4

4
drawSomeThings(localView.getGraphics());

Don't use the getGraphics() method to do painting. The painting will be lost the next time Swing determines the components needs to be repainted.

Instead custom painting is done by overriding the paintComponent() method of your component.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Ah, so I should be extending JPanel (or JComponent) rather than drawing to the JPanel directly? – Vinay Nov 09 '11 at 15:19
  • Yes. The [Custom Painting](http://download.oracle.com/javase/tutorial/uiswing/painting/step2.html) tutorial steps you through the process. – camickr Nov 09 '11 at 15:42
2
  1. Do not use setPreferredSize method, here's a related thread.
  2. Do not specify explicetly the size of the JScrollPane with setBounds. Let the LayoutManager of it's parent take care of this.
  3. JScrollPane should use a ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED by default. So the scrollbar should appear automatically when the preferred size of the child component is higher than the displayed area. Try to revalidate the JScrollPane instead of the JPanel.
Community
  • 1
  • 1
Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • I understand that normally you are supposed to use a LayoutManager; but I don't see how one would help in this case. I am drawing onto the localView which is a surface that needs to be growable; it's basically just a canvas, and I don't know of a LayoutManager that will detect if I draw past the bounds of the panel's graphics object. – Vinay Nov 09 '11 at 15:14
  • Look at @camickr's answer. I think that could be your problem. Btw, you should always use a proper layout manager and don't use setXXXMethods from your application code. Soon or less you'll have a lot of trouble if you build your gui relying on those methods. – Heisenbug Nov 09 '11 at 15:17
0

It would appear that redraw is being called at some point, I've not used swing for a while so I'm not entirely sure what the problem is but try debugging and running through the code step by step to see where redraw is being called would be a good starting place.

mmoon
  • 222
  • 1
  • 12
  • Do you mean redraw or repaint? I do think it is calling repaint() as part of the revalidate (will need to check to make sure) or when I scroll the bars. But even knowing that it calls repaint(), what is the solution? Do I just need to draw everything back onto the localView's graphics object, or is there a better way? Manually redrawing everything that I do each time the user scrolls is inefficient and very slow if they are using the arrow keys to scroll, for example. – Vinay Nov 09 '11 at 15:05
  • Like I said, it has been a while since I used swing etc so I'm pretty rusty on what may be the issue, but it is likely repaint() is the method which is being called. I'm not sure what is the best way to go, obviously repainting the screen is in-efficient but at least it would work, I just thought that pointing you in the right direction may help you, sorry. – mmoon Nov 09 '11 at 15:12
  • I certainly appreciate the help. Thanks :-) – Vinay Nov 09 '11 at 15:21
0

you should certainly use repaint instead of revalidate. revalidate only marks all the container upto the top level as invalid.

Amritpal Singh
  • 1,765
  • 1
  • 13
  • 20