Java
Swing
revalidate
repaint
GUI

Java Swing revalidate vs repaint

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

revalidate() tells the layout manager to recalculate component sizes and positions. repaint() schedules the component for visual redrawing on screen. When you add, remove, or resize components, you typically need both: revalidate() to fix the layout, then repaint() to render the updated result. Calling only one of them is the most common source of "invisible component" or "stale display" bugs in Swing applications.

What revalidate() Does

revalidate() marks a component as needing layout recalculation. It walks up the containment hierarchy to find the nearest "validate root" (usually a JRootPane), then schedules a validate() call on the Event Dispatch Thread (EDT). During validation, the layout manager calls getPreferredSize(), getMinimumSize(), and getMaximumSize() on each child component and assigns new bounds via setBounds().

java
1// After adding a component, revalidate triggers layout recalculation
2JPanel panel = new JPanel(new FlowLayout());
3JLabel label = new JLabel("New Label");
4panel.add(label);
5
6// Without this call, the label has zero bounds and won't appear
7panel.revalidate();

Internally, revalidate() calls RepaintManager.addInvalidComponent(this), which coalesces multiple layout requests into a single layout pass. This means calling revalidate() ten times in a row does not produce ten layout passes.

When to Call revalidate()

  • After calling add() or remove() on a container
  • After changing a component's preferred/minimum/maximum size
  • After modifying a border that affects insets
  • After swapping a layout manager on a container
  • After changing properties that affect a component's size (e.g., text on a JLabel that uses its preferred size)

What repaint() Does

repaint() schedules a paint request. It does not paint immediately. Instead, it posts a request to the EDT's paint queue, which the RepaintManager coalesces into a single paintComponent() call. The actual painting sequence for a JComponent is:

  1. paintComponent(Graphics g) - draws the component itself
  2. paintBorder(Graphics g) - draws the border
  3. paintChildren(Graphics g) - recursively paints child components
java
1// Custom painting example
2public class GradientPanel extends JPanel {
3    private Color startColor = Color.BLUE;
4
5    public void setStartColor(Color color) {
6        this.startColor = color;
7        repaint(); // Schedule visual update, no layout change needed
8    }
9
10    @Override
11    protected void paintComponent(Graphics g) {
12        super.paintComponent(g);
13        Graphics2D g2 = (Graphics2D) g;
14        g2.setPaint(new GradientPaint(0, 0, startColor, getWidth(), getHeight(), Color.WHITE));
15        g2.fillRect(0, 0, getWidth(), getHeight());
16    }
17}

When to Call repaint()

  • After changing a visual property (color, font, icon) that does not affect layout
  • After updating custom painting state (animation frames, selection highlighting)
  • After revalidate() when components have been structurally modified
  • When a model change should be reflected visually (e.g., table data changed)

Why You Usually Need Both

When the component hierarchy changes, the layout must be recalculated (revalidate()) and then the new layout must be rendered (repaint()). Calling only revalidate() can leave stale pixels on screen because the repaint region may not cover the old component locations. Calling only repaint() without revalidate() will redraw components at their old positions and sizes.

java
1import javax.swing.*;
2import java.awt.*;
3
4public class DynamicPanel {
5    private int count = 0;
6    private final JPanel content = new JPanel(new FlowLayout());
7
8    public void createAndShowGUI() {
9        JFrame frame = new JFrame("revalidate + repaint Demo");
10        JButton addBtn = new JButton("Add Label");
11        JButton removeBtn = new JButton("Remove Last");
12
13        addBtn.addActionListener(e -> {
14            content.add(new JLabel("Item " + (++count)));
15            content.revalidate();  // Recalculate layout for the new label
16            content.repaint();     // Redraw the panel with updated layout
17        });
18
19        removeBtn.addActionListener(e -> {
20            if (content.getComponentCount() > 0) {
21                content.remove(content.getComponentCount() - 1);
22                content.revalidate();  // Recalculate layout without the removed label
23                content.repaint();     // Clear the area where the label was
24            }
25        });
26
27        JPanel buttons = new JPanel();
28        buttons.add(addBtn);
29        buttons.add(removeBtn);
30
31        frame.setLayout(new BorderLayout());
32        frame.add(new JScrollPane(content), BorderLayout.CENTER);
33        frame.add(buttons, BorderLayout.SOUTH);
34        frame.setSize(400, 300);
35        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
36        frame.setVisible(true);
37    }
38
39    public static void main(String[] args) {
40        SwingUtilities.invokeLater(() -> new DynamicPanel().createAndShowGUI());
41    }
42}

Comparison Table

Aspectrevalidate()repaint()
PurposeRecalculate layout (sizes, positions)Redraw visual appearance (pixels)
TriggersComponent add/remove, size changesColor, font, icon, or painting state changes
Defined inJComponent (overrides Component.invalidate())Component
What it schedulesvalidate() on the nearest validate rootpaintComponent(), paintBorder(), paintChildren()
CoalescingYes, via RepaintManager.addInvalidComponent()Yes, via RepaintManager.addDirtyRegion()
Thread safetyMust be called on EDT (or it posts to EDT)Can be called from any thread (posts to EDT internally)
Effect without the otherLayout updates but old pixels may remainRedraws at old positions/sizes

The RepaintManager Under the Hood

Both methods are managed by javax.swing.RepaintManager, which batches and optimizes UI updates. Understanding this helps explain why Swing remains responsive even when code calls revalidate() and repaint() frequently.

java
1// RepaintManager coalesces updates automatically
2for (int i = 0; i < 100; i++) {
3    panel.add(new JLabel("Label " + i));
4}
5// One revalidate + repaint is sufficient for all 100 additions
6panel.revalidate();
7panel.repaint();
8
9// DO NOT call revalidate/repaint inside the loop - it works but wastes cycles
10// The RepaintManager would coalesce them anyway, but the overhead of
11// 100 addInvalidComponent calls is unnecessary

The RepaintManager also handles double buffering. When repaint() fires, Swing paints to an off-screen buffer first, then copies the buffer to the screen in a single operation. This prevents flickering, which was a major problem with AWT's immediate-mode painting.

Thread Safety Rules

Swing is single-threaded by design. All UI modifications must happen on the Event Dispatch Thread.

java
1// WRONG: modifying UI from a background thread
2new Thread(() -> {
3    panel.add(new JLabel("From background"));
4    panel.revalidate();
5    panel.repaint();
6}).start();
7
8// CORRECT: use SwingUtilities.invokeLater
9new Thread(() -> {
10    // ... do heavy computation ...
11    SwingUtilities.invokeLater(() -> {
12        panel.add(new JLabel("From EDT"));
13        panel.revalidate();
14        panel.repaint();
15    });
16}).start();
17
18// ALSO CORRECT: use SwingWorker
19SwingWorker<List<String>, String> worker = new SwingWorker<>() {
20    @Override
21    protected List<String> doInBackground() {
22        // Background work here
23        return List.of("Result 1", "Result 2");
24    }
25
26    @Override
27    protected void done() {
28        // Runs on EDT automatically
29        try {
30            for (String item : get()) {
31                panel.add(new JLabel(item));
32            }
33            panel.revalidate();
34            panel.repaint();
35        } catch (Exception ex) {
36            ex.printStackTrace();
37        }
38    }
39};
40worker.execute();

Note that repaint() is one of the few Swing methods that is safe to call from any thread, because it only posts a request to the EDT queue. However, revalidate() should still be called from the EDT.

Common Pitfalls

  • Calling only revalidate() after adding components. The new components get correct bounds but old pixels from the previous layout may remain visible, creating ghost artifacts. Always pair with repaint().
  • Calling only repaint() after adding components. The paint cycle renders components at their old (or zero) bounds. The new component will be invisible or drawn at (0,0) with zero size.
  • Calling revalidate() and repaint() inside a tight loop. While RepaintManager coalesces these calls, the overhead of posting hundreds of requests is wasteful. Make all structural changes first, then call both methods once.
  • Calling repaint() inside paintComponent(). This creates an infinite repaint loop that pegs the CPU at 100%. Use a javax.swing.Timer for animations instead.
  • Modifying the UI from a non-EDT thread. This causes race conditions that produce intermittent rendering glitches, exceptions, or deadlocks. Use SwingUtilities.invokeLater() or SwingWorker.
  • Forgetting to call super.paintComponent(g) in custom painting. Without this call, the background is not cleared, leading to visual smearing as old content bleeds through.

Summary

revalidate() handles layout: it tells the layout manager to recompute where everything goes. repaint() handles rendering: it schedules the component to be redrawn on screen. After any structural change to the component tree (adding, removing, or resizing children), call revalidate() followed by repaint(). For purely visual changes that do not affect layout (color, custom painting), repaint() alone is sufficient. Both methods are coalesced by RepaintManager to avoid redundant work, and both must be invoked on the Event Dispatch Thread (with repaint() being the exception that can safely be called from any thread). Getting this pair right eliminates the most common category of Swing rendering bugs.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.