Answer: You need to declare a getPreferredSize() method
in your JPanels. pack() causes the layout manager to consult this method.
pack() may ignore dimensions that were set using the setSize()
command.
Answer: Use the getGraphics() method.
Answer: You are probably not calling repaint on the correct component. You
must call repaint on the component that you want redrawn. For example, if
you want a JPanel redrawn, you should call repaint on that JPanel. If you
instead try to call repaint on the JFrame containing that JPanel, or on
the content pane containing that JPanel, nothing will happen because
neither of them will ask their own components to redraw themselves.
Answer: You may have omitted a call to super.paintComponent(g)
from your paintComponent method. Failing to call the superclass method
causes all sorts of strange drawing behavior.
Answer: The way I determine the difference is to have the application
define a boolean flag which it sets to true when it calls repaint.
paintComponent tests this flag and then re-sets it to false. If someone
has a better way of doing this, I'd be happy to hear about it.
Answer: Java does strange things with the clip region. Before Java calls
paintComponent, it tiles the clip region with a previous image of the window.
As far as I can tell, you cannot prevent Java from doing this. Therefore
you might as well call super.paintComponent to blank the clipping region,
then redraw into that clipping region. In order to control the clipping
region that you are given, give a damaged region to the repaint method when
you call it. If you don't, Java assumes the clipping region should be the
entire component. Java uses the RepaintManager class to collect damaged
regions. Each time that your application calls repaint, an instance of
the RepaintManager gets called and it folds the dirty region specified by
repaint into the existing dirty region for the component. It appears that
the RepaintManager can only maintain one region per component. Unfortunately,
this means that it is difficult to implement a display manager that only
redraws changed objects, because the union of the changed objects' bounding
boxes will typically include some undamaged objects. One way to avoid this
problem is call paintImmediately rather than repaint but the Java documentation
does not suggest doing this. In your sokoban game, the changed objects
will always be contiguous so you can get away with drawing only the changed
objects. One other trick that you might try but which won't work is to
give repaint a tiny damaged region and then try to enlarge the clipping
region in paintComponent. Java won't let you enlarge the clipping region,
you can only narrow it.
Answer: The documentation for a JScrollPane says that it gets its
sizing information from the getPreferredScrollableViewportSize
method. This method returns a Dimension so we can return a Dimension
object with the desired width. Unfortunately, we may still want the
default height. According to the documentation, the default height
accommodates 8 rows. In order to calculate the number of pixels needed to
display 8 rows, the default implementation of
getPreferredScrollableViewportSizemethod uses 16 pixels per row. Hence
the default height is 128 pixels and you can get your desired scroll pane
using the following code:
JList myList = new JList() { public Dimension getPreferredScrollableViewportSize() { return new Dimension(desiredWidth, 128); } }
Answer: An instance of an inner class can access instance variables of
its enclosing class which means that it needs to have an instance of
its enclosing class as a "scope". However, if you try to create an
instance of an inner class from another class, Java does not have
such an outer object to provide as a scope. Hence only the class containing
an inner class can create instances of its inner classes.
Answer: clearRect does not seem to be a reliable way to clear a display
area. If you are writing to an off-screen image, which is what you are
doing by default since JFrames are double-buffered by default, then
clearRect is not guaranteed to be correct, but it appears to fail in other
situations as well. The best way to clear an area is
to retrieve the background color from the JComponent, set
the color to this background color, and then call fillRect. For example:
void paintComponent(Graphics g) { ... g.setColor(getBackground()); // this command clears the entire component. To clear a smaller area you // would provide your own coordinates and size. g.fillRect(0, 0, getWidth(), getHeight()); ... }