Paint Component Method
The RandomStringsPanel draws 25 messages, each with a random color, position, and one of five random fonts, on a black background.
A Picture That Changes on Its Own
This article looks at a Java panel that displays 25 copies of a message. Each copy is drawn with a color and position chosen at random, and each copy uses a font randomly chosen from among five possible fonts. The messages sit on a black background. The source describes this as a small challenge in custom graphics, and its documentation points out a subtle behavior of the panel. That behavior is the focus of this article.
What do you think happens?
You run the panel, then minimize the window and restore it. Will the 25 messages appear in exactly the same colors, positions, and fonts as before?
Reveal answer
No, the random choices are made again when the panel is redrawn
The panel does not draw its 25 messages once and keep the result. Its painting logic lives in paintComponent(), so the random color, position, and font for each message are chosen during painting. Each time Java asks the component to redraw itself, the painting logic runs again and makes a new set of random choices.
The Assumption That Random Values Are Picked Once
When people first read code that uses random numbers, they often assume the random values are picked once, when the object is created, and then stay fixed. Under that belief, the picture would look the same every time it appears on screen. The guess is a reasonable one, because most programs produce a stable result once they have computed it. A panel that paints itself is different: its result is computed again whenever it is painted.
Where Swing Calls paintComponent()
paintComponent() is the method responsible for painting a Swing component, and it is called every time the component is redrawn. You do not call it yourself in the normal flow of a program. Swing calls it when the panel needs to be drawn. Three triggers are the usual reasons: the panel is displayed for the first time, the window is resized or an area of it is exposed after being covered, and the program explicitly asks for a redraw by calling repaint().
Because the trigger can happen many times over the life of a panel, paintComponent() can run many times as well. The diagram below traces the sequence of events. Read it from top to bottom and count how many times the painting step appears.
What the JPanel Subclass Contributes
The panel is a Swing component. The source imports the Swing JPanel class and declares the panel as a class that extends it. A JPanel is described in the source as a container that can hold other components. Because RandomStringsPanel extends JPanel, it inherits that base behavior and adds its own painting logic on top. The programmer's job is to override paintComponent() so that the panel draws its own content, while the Swing framework decides when that override is called.
The sketch below is an illustrative outline written for this article to show the shape of such a class. It is not the course's own listing, and the details of the drawing are simplified. The key structural points are the extends clause and the overridden paintComponent() method that receives a Graphics object.
- extends
JPanel: inherits the base panel behavior paintComponent(Graphics g): the painting method the framework callssuper.paintComponent(g): hands the base painting work toJPanelfirstrandom.nextIntcalls: choices made inside the painting method, so each call differs
Two Redraws, Two Pictures
Consider two consecutive calls to paintComponent() on the same panel. The code between the calls is identical, yet the two pictures differ. The reason is that each call starts fresh and asks the random generator for new values. The diagram below shows the change between the first call and the second. The values in the caption are illustrative; the point is that the set of choices is regenerated, not reused.
Tracing a single message through two redraws
The panel is redrawn twice. Trace what happens to the first of the 25 messages on each redraw, and decide whether its color, position, and font match from one redraw to the next.
- 1Step 1: first redraw starts
Swing calls
paintComponent(). The loop begins at message 1. - 2Step 2: first choices are made
Inside the loop, the random color, position, and font for message 1 are selected during this call.
- 3Step 3: first redraw finishes
All 25 messages are drawn. The choices made in this call exist only for this picture.
- 4Step 4: second redraw starts
A later trigger causes Swing to call
paintComponent()again. The loop begins again at message 1. - 5Step 5: second choices are made
The random generator is asked again, so message 1 receives a new color, position, and font.
Message 1 is not guaranteed to match its earlier appearance. The code is the same, but the painting method makes new random choices each time it runs.
Following a Repaint From Request to Pixels
When a drawing does not match what you expected, the useful question is where the result stopped following your mental model. For this panel, the random choices are made inside the painting method, not at setup. The flow below follows a single redraw from its trigger to the pixels on screen. Each step is a place where your expectation could break, and the random choices sit in the middle of the flow.
Read the flow as a diagnostic tool. If you expected the same picture every time, the divergence is at the random choices step, because that is where the values are selected. Looking at the constructor or the class declaration will not reveal this, since those parts do not make the choices shown on screen.
Mistakes When Tracing a Divergent Drawing
Common mistake Assuming random values are set once in the constructor
What it looks likeLooking only at the constructor and concluding the 25 colors are fixed when the panel is created.
Why it failsIn this panel the random choices are made during painting, so the constructor does not determine what appears on screen.
Do this insteadTrace the painting method and look for where the random calls occur.
Common mistake Tracing only the first drawing
What it looks likeStepping through one run of paintComponent() and assuming every later picture will match it.
Why it failsA trace that stops after the first drawing cannot show why later pictures differ.
Do this insteadFollow what happens between two redraws, including the second call and its new random choices.
Common mistake Expecting old messages to disappear without clearing
What it looks likeOmitting the call that clears the background, so each redraw adds 25 new messages on top of the previous ones.
Why it failsDrawing does not erase earlier drawing on its own.
Do this insteadCall super.paintComponent(g) at the start of the override so the previous frame is cleared before new messages are drawn.
Common mistake Treating the redraw trigger as something the painting method controls
Tracing the Redraws Yourself
A teammate says that the RandomStringsPanel should show the same 25 messages every time the window is restored after being minimized, because the random numbers were already generated when the program started. Write a short explanation that tests this claim. Identify which method runs on restore, where the random values are chosen, and whether the claim holds.
Hints
- Ask which method Swing calls when the window is restored or exposed.
- Find the lines that call the random generator and check which method they are inside.
- Compare what happens on the first display with what happens on the second.
Name the three triggers that can cause paintComponent() to run, and for each one say which step of the repaint flow it passes through before the random choices are made.
Hints
- The triggers are the first display, a resize or exposure, and an explicit
repaint()call. - All three lead to Swing dispatching a redraw to the panel.
Key Takeaways
- The
RandomStringsPaneldraws 25 messages, each with a random color, position, and one of five random fonts, on a black background. paintComponent()is called by the Swing framework every time the component is redrawn, so the random choices made inside it are regenerated on each redraw.RandomStringsPanelextendsJPaneland overridespaintComponent(), inheriting the base panel behavior and adding its own painting logic.- When a result diverges from expectation, trace when the painting method runs rather than looking only at setup code such as the constructor.
- Clearing the previous frame with
super.paintComponent(g)keeps earlier drawing from accumulating under the new messages.