Concepts / Paint Component Method

Paint Component Method

The RandomStringsPanel draws 25 messages, each with a random color, position, and one of five random fonts, on a black background.

  • Programming

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?

  • Yes, the picture is saved once and reused

  • No, the random choices are made again when the panel is redrawn

Reveal answer
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.

Triggerfirst display, resize, orrepaint()Swing frameworkdecides the panel must bedrawnRandomStringsPanelits paintComponent() methodFirst paint25 new random choicesNext paint25 new random choices againrequests a redrawcalls paintComponent()draws 25 messagesanother trigger later
What sequence of events causes paintComponent() to be called, and how many times does it run over the life of the panel? Each trigger leads through Swing to a fresh run of the painting method.

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.

java
Notes on the code
  • extends JPanel: inherits the base panel behavior
  • paintComponent(Graphics g): the painting method the framework calls
  • super.paintComponent(g): hands the base painting work to JPanel first
  • random.nextInt calls: 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.

First call25 messages with one set ofchoicesSecond call25 messages with a new setof choicesMessage 1 choicesone color, position, fontMessage 1 choicesa different color,position, fontrandom picksrandom picks again
What changes between two consecutive calls to paintComponent(), and why does the output differ even though the code is identical? Each call makes its own set of random color, position, and font choices.
Worked example

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.

  1. 1
    Step 1: first redraw starts

    Swing calls paintComponent(). The loop begins at message 1.

  2. 2
    Step 2: first choices are made

    Inside the loop, the random color, position, and font for message 1 are selected during this call.

  3. 3
    Step 3: first redraw finishes

    All 25 messages are drawn. The choices made in this call exist only for this picture.

  4. 4
    Step 4: second redraw starts

    A later trigger causes Swing to call paintComponent() again. The loop begins again at message 1.

  5. 5
    Step 5: second choices are made

    The random generator is asked again, so message 1 receives a new color, position, and font.

Result

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.

Event triggerdisplay, resize, orrepaint()Repaint queueSwing schedules the redrawpaintComponent()runs for this redrawRandom choicescolor, position, font permessagedrawString()draws each messagePixels on screenone picture for this redrawrequestdispatchinside the loopchoices applieddrawn
Where does a drawing result diverge from expectation, and at which step in the flow does it happen? The divergence sits at the random choice step inside paintComponent(), not in the constructor or class declaration.

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 like

    Looking only at the constructor and concluding the 25 colors are fixed when the panel is created.

    Why it fails

    In this panel the random choices are made during painting, so the constructor does not determine what appears on screen.

    Do this instead

    Trace the painting method and look for where the random calls occur.

  • Common mistake

    Tracing only the first drawing

    What it looks like

    Stepping through one run of paintComponent() and assuming every later picture will match it.

    Why it fails

    A trace that stops after the first drawing cannot show why later pictures differ.

    Do this instead

    Follow 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 like

    Omitting the call that clears the background, so each redraw adds 25 new messages on top of the previous ones.

    Why it fails

    Drawing does not erase earlier drawing on its own.

    Do this instead

    Call 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

MEDIUM

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.
EASY

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 RandomStringsPanel draws 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.
  • RandomStringsPanel extends JPanel and overrides paintComponent(), 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.